Deskripsi BOL dari CTE rekursif menggambarkan semantik eksekusi rekursif adalah sebagai berikut:
- Membagi ekspresi CTE menjadi anggota jangkar dan rekursif.
- Jalankan anggota anchor (s) membuat set doa pertama atau hasil basis (T0).
- Jalankan anggota rekursif dengan Ti sebagai input dan Ti + 1 sebagai output.
- Ulangi langkah 3 hingga set kosong dikembalikan.
- Kembalikan set hasil. Ini adalah UNION ALL dari T0 hingga Tn.
Perhatikan di atas adalah deskripsi yang logis . Urutan fisik operasi dapat agak berbeda seperti yang diilustrasikan di sini
Menerapkan ini ke CTE Anda, saya akan mengharapkan loop tak terbatas dengan pola berikut
+-----------+---------+---+---+---+
| Invocation| Results |
+-----------+---------+---+---+---+
| 1 | 1 | 2 | 3 | |
| 2 | 4 | 5 | | |
| 3 | 1 | 2 | 3 | |
| 4 | 4 | 5 | | |
| 5 | 1 | 2 | 3 | |
+-----------+---------+---+---+---+
Karena
select a
from cte
where a in (1,2,3)
adalah ekspresi Anchor. Ini jelas kembali 1,2,3
sebagaiT0
Setelah itu ekspresi rekursif berjalan
select a
from cte
except
select a
from r
Dengan 1,2,3
sebagai input yang akan menghasilkan output 4,5
saat T1
kemudian memasukkan kembali untuk putaran rekursi berikutnya akan kembali 1,2,3
dan seterusnya tanpa batas.
Namun, ini bukan yang sebenarnya terjadi. Ini adalah hasil dari 5 doa pertama
+-----------+---------+---+---+---+
| Invocation| Results |
+-----------+---------+---+---+---+
| 1 | 1 | 2 | 3 | |
| 2 | 1 | 2 | 4 | 5 |
| 3 | 1 | 2 | 3 | 4 |
| 4 | 1 | 2 | 3 | 5 |
| 5 | 1 | 2 | 3 | 4 |
+-----------+---------+---+---+---+
Dari menggunakan OPTION (MAXRECURSION 1)
dan menyesuaikan ke atas secara bertahap 1
dapat dilihat bahwa ia memasuki siklus di mana setiap tingkat berturut-turut akan terus berganti antara keluaran 1,2,3,4
dan 1,2,3,5
.
Seperti yang dibahas oleh @Quassnoi di posting blog ini . Pola hasil yang diamati adalah seolah-olah setiap doa melakukan di (1),(2),(3),(4),(5) EXCEPT (X)
mana X
adalah baris terakhir dari doa sebelumnya.
Sunting: Setelah membaca jawaban SQL Kiwi yang sangat baik jelas mengapa ini terjadi dan bahwa ini bukan keseluruhan cerita karena masih ada banyak hal yang tersisa di tumpukan yang tidak pernah dapat diproses.
Anchor Emits 1,2,3
ke Konten Stack klien3,2,1
3 muncul tumpukan, Stack Contents 2,1
LASJ kembali 1,2,4,5
, Stack Contents5,4,2,1,2,1
5 muncul tumpukan, Stack Contents 4,2,1,2,1
LASJ mengembalikan 1,2,3,4
Stack Contents4,3,2,1,5,4,2,1,2,1
4 muncul tumpukan, Isi Stack 3,2,1,5,4,2,1,2,1
LASJ mengembalikan 1,2,3,5
Stack Contents5,3,2,1,3,2,1,5,4,2,1,2,1
5 muncul tumpukan, Stack Contents 3,2,1,3,2,1,5,4,2,1,2,1
LASJ mengembalikan 1,2,3,4
Stack Contents
4,3,2,1,3,2,1,3,2,1,5,4,2,1,2,1
Jika Anda mencoba dan mengganti anggota rekursif dengan ekspresi yang setara secara logis (tanpa adanya duplikat / NULL)
select a
from (
select a
from cte
where a not in
(select a
from r)
) x
Ini tidak diizinkan dan memunculkan kesalahan "Referensi rekursif tidak diizinkan di subqueries." jadi mungkin itu adalah pengawasan yang EXCEPT
bahkan diizinkan dalam kasus ini.
Tambahan:
Microsoft sekarang telah menanggapi Umpan Balik Koneksi saya seperti di bawah ini
Tebakan Jack benar: ini seharusnya kesalahan sintaksis; referensi rekursif memang seharusnya tidak diizinkan dalam EXCEPT
klausa. Kami berencana untuk mengatasi bug ini dalam rilis layanan mendatang. Sementara itu, saya menyarankan untuk menghindari referensi berulang dalam EXCEPT
klausa.
Dalam membatasi rekursi EXCEPT
kita mengikuti standar SQL ANSI, yang telah memasukkan pembatasan ini sejak rekursi diperkenalkan (pada tahun 1999 saya percaya). Tidak ada kesepakatan luas tentang apa yang semantik harus untuk rekursi EXCEPT
(juga disebut "negasi unstratified") dalam bahasa deklaratif seperti SQL. Selain itu, sangat sulit (jika bukan tidak mungkin) untuk mengimplementasikan semantik seperti itu secara efisien (untuk basis data berukuran cukup) dalam sistem RDBMS.
Dan sepertinya implementasi akhirnya dibuat pada 2014 untuk database dengan tingkat kompatibilitas 120 atau lebih tinggi .
Referensi rekursif dalam klausa KECUALI menghasilkan kesalahan dalam kepatuhan dengan standar SQL ANSI.