EDIT
Ketika Anda membaca dokumentasi CTE mengenai rekursi, Anda akan melihat bahwa ia memiliki beberapa batasan, seperti tidak dapat menggunakan subquery, group-by, top. Ini semua melibatkan banyak baris. Dari pengujian terbatas, dan memeriksa rencana eksekusi, serta menguji kueri ini
with cte as (
select 1 a, 1 b union all select 1, 2 union all select 1, 3 union all select 2, 4
)
, rcte (a, b, c, d) as (
select a, b, cast(0 as int), 1
from cte
union all
select r.a, cte.b, cast(ROW_NUMBER() over (order by r.b) as int), r.d+1
from rcte r inner join cte on cte.a=r.a
where r.d < 2
)
select *
from rcte
where d=2
order by a, b
Saya hanya bisa menyimpulkan:
- Row_Number() berfungsi di CTE, ketika tabel lain digabungkan untuk menghasilkan kumpulan hasil multi-baris
- Dari hasil penomoran, jelas bahwa CTE diproses dalam satu baris melalui semua iterasi, baris demi baris, bukan multibaris demi multibaris, meskipun tampaknya mengulangi semua baris secara bersamaan. Ini akan menjelaskan mengapa salah satu fungsi yang berlaku untuk operasi multi-baris tidak diizinkan untuk CTE rekursif.
Meskipun saya sampai pada kesimpulan ini dengan mudah, seseorang jelas membutuhkan lebih banyak waktu untuk jelaskan dengan sangat detail hanya 17 bulan yang lalu...
Dengan kata lain, ini adalah sifat implementasi SQL Server dari CTE rekursif, jadi fungsi windowing tidak akan bekerja seperti yang Anda harapkan.
Untuk kepentingan orang lain, outputnya adalah:
a b c d
----------- ----------- ----------- -----------
1 1 1 2
1 2 1 2
2 3 1 2
2 4 1 2
Sedangkan Anda mengharapkan c berisi 1,2,1,2 bukannya 1,1,1,1. Ini jelas merupakan bug, karena tidak ada dokumentasi yang mengatakan bahwa fungsi windowing tidak boleh bekerja di bagian rekursif dari CTE.
Catatan:row_number() mengembalikan bigint, jadi Anda hanya dapat menggunakan jangkar(c) sebagai bigint.
Karena setiap iterasi meningkat d, Anda dapat melakukan windowing di luar.
with cte as (
select 1 a, 1 b union all select 1, 2 union all select 2, 3 union all select 2, 4
)
, rcte (a, b, d) as (
select a, b, 1
from cte
union all
select a, b, d+1
from rcte
where d < 2
)
select a,b, ROW_NUMBER() over (partition by a,d order by b) c,d
from rcte
--where d=2
order by d, a, b
EDIT - wawasan
Saat menjawab pertanyaan lain , saya bermain lagi dengan CTE rekursif. Jika Anda menjalankannya tanpa ORDER BY akhir, Anda dapat melihat bagaimana SQL Server mendekati rekursi. Sangat menarik bahwa ia mundur dalam kasus ini, kemudian melakukan rekursi mendalam-pertama penuh pada setiap baris.
Tabel contoh
create table Testdata(SomeID int, OtherID int, Data varchar(max))
insert Testdata select 1, 9, '18,20,22,alpha,beta,gamma,delta'
insert Testdata select 2, 6, ''
insert Testdata select 3, 8, '11,12,.'
insert Testdata select 4, 7, '13,19,20,66,12,232,1232,12312,1312,abc,def'
insert Testdata select 5, 8, '17,19'
Kueri rekursif
;with tmp(SomeID, OtherID, DataItem, Data) as (
select SomeID, OtherID, LEFT(Data, CHARINDEX(',',Data+',')-1),
STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from Testdata
union all
select SomeID, OtherID, LEFT(Data, CHARINDEX(',',Data+',')-1),
STUFF(Data, 1, CHARINDEX(',',Data+','), '')
from tmp
where Data > ''
)
select SomeID, OtherID, DataItem, Data
from tmp
-- order by SomeID
Output menunjukkan jangkar CTE diproses dalam iterasi satu, lalu untuk alasan apa pun setiap baris dalam kumpulan jangkar diulang hingga selesai (kedalaman-pertama) sebelum memproses baris lainnya.
Namun itu memang memiliki kegunaan yang aneh, seperti jawaban ini pertunjukan