Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

cte rekursif dengan fungsi peringkat

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:

  1. Row_Number() berfungsi di CTE, ketika tabel lain digabungkan untuk menghasilkan kumpulan hasil multi-baris
  2. 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




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hubungkan SQL Server 2008 ke Kalender Outlook?

  2. Cara Tercepat untuk Menjalankan Kueri yang Sama Beberapa Kali di SQL Server

  3. ACOS() Contoh di SQL Server

  4. Kesalahan Login SQL Server:Login gagal untuk pengguna 'NT AUTHORITY\SYSTEM'

  5. Penyisipan Massal Daftar Generik C# ke SQL Server