คำอธิบาย BOL ของ CTE แบบเรียกซ้ำจะอธิบายความหมายของการเรียกใช้แบบเรียกซ้ำดังนี้:
- แยกการแสดงออกของ CTE ออกเป็นจุดยึดและสมาชิกแบบเรียกซ้ำ
- เรียกใช้สมาชิกจุดยึดสร้างการเรียกครั้งแรกหรือชุดผลลัพธ์พื้นฐาน (T0)
- รันสมาชิกแบบเรียกซ้ำโดยใช้ Ti เป็นอินพุตและ Ti + 1 เป็นเอาต์พุต
- ทำซ้ำขั้นตอนที่ 3 จนกว่าจะส่งคืนชุดเปล่า
- ส่งคืนชุดผลลัพธ์ นี่คือยูเนี่ยนทั้งหมดของ T0 ถึง Tn
หมายเหตุข้างต้นเป็นคำอธิบายเชิงตรรกะ ลำดับทางกายภาพของการดำเนินการอาจแตกต่างกันบ้างดังที่แสดงไว้ที่นี่
การนำสิ่งนี้ไปใช้กับ CTE ของคุณฉันคาดหวังว่าวงวนไม่สิ้นสุดที่มีรูปแบบต่อไปนี้
+-----------+---------+---+---+---+
| Invocation| Results |
+-----------+---------+---+---+---+
| 1 | 1 | 2 | 3 | |
| 2 | 4 | 5 | | |
| 3 | 1 | 2 | 3 | |
| 4 | 4 | 5 | | |
| 5 | 1 | 2 | 3 | |
+-----------+---------+---+---+---+
เพราะ
select a
from cte
where a in (1,2,3)
คือการแสดงออก Anchor ผลตอบแทนนี้ชัดเจน1,2,3
ว่าเป็นT0
หลังจากนั้นนิพจน์แบบเรียกใช้ซ้ำจะทำงาน
select a
from cte
except
select a
from r
ด้วยการ1,2,3
ป้อนข้อมูลที่จะให้ผลลัพธ์ของการ4,5
เป็นT1
แล้วเสียบที่ย้อนกลับไปในรอบถัดไปของการเรียกซ้ำจะกลับมา1,2,3
เรื่อย ๆ
นี่ไม่ใช่สิ่งที่เกิดขึ้นจริงอย่างไรก็ตาม นี่คือผลลัพธ์ของการเชิญ 5 ครั้งแรก
+-----------+---------+---+---+---+
| 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 |
+-----------+---------+---+---+---+
จากการใช้OPTION (MAXRECURSION 1)
และการปรับขึ้นในการเพิ่มขึ้นของ1
มันจะเห็นได้ว่าจะเข้าสู่รอบที่แต่ละระดับอย่างต่อเนื่องต่อเนื่องจะสลับระหว่าง outputting และ1,2,3,4
1,2,3,5
ตามที่กล่าวถึงโดย@Quassnoiในบล็อกโพสต์นี้ รูปแบบของผลลัพธ์ที่สังเกตได้จะเหมือนกับว่าการร้องขอแต่ละครั้งกำลังทำ(1),(2),(3),(4),(5) EXCEPT (X)
อยู่โดยที่X
แถวสุดท้ายจากการร้องขอก่อนหน้านี้
แก้ไข:หลังจากอ่านคำตอบที่ยอดเยี่ยมของ SQL Kiwiมันชัดเจนว่าทำไมทั้งสองเกิดเหตุการณ์นี้ขึ้นและนี่ไม่ใช่เรื่องราวทั้งหมดที่ยังมีสิ่งของเหลืออยู่ในสแต็กที่ไม่สามารถประมวลผลได้
Anchor ปล่อย1,2,3
ให้กับลูกค้าสแต็คเนื้อหา3,2,1
3 สแตกออกจากกองเนื้อหาสแต็ค 2,1
LASJ ส่งคืน1,2,4,5
เนื้อหาสแต็ก5,4,2,1,2,1
5 สแตกออกจากกองเนื้อหาสแต็ค 4,2,1,2,1
LASJ ส่งคืน1,2,3,4
เนื้อหาสแต็ก4,3,2,1,5,4,2,1,2,1
สแตก 4 ครั้งออกจากสแต็กเนื้อหาสแต็ก 3,2,1,5,4,2,1,2,1
LASJ ส่งคืน1,2,3,5
เนื้อหาสแต็ก5,3,2,1,3,2,1,5,4,2,1,2,1
5 สแตกออกจากกองเนื้อหาสแต็ค 3,2,1,3,2,1,5,4,2,1,2,1
LASJ ส่งคืน1,2,3,4
เนื้อหาสแต็ก
4,3,2,1,3,2,1,3,2,1,5,4,2,1,2,1
ถ้าคุณลองและแทนที่สมาชิกแบบเรียกซ้ำด้วยนิพจน์เชิงตรรกะ (โดยไม่มีนิพจน์ซ้ำ / NULL)
select a
from (
select a
from cte
where a not in
(select a
from r)
) x
สิ่งนี้ไม่ได้รับอนุญาตและทำให้เกิดข้อผิดพลาด "ไม่อนุญาตให้มีการอ้างอิงแบบเรียกซ้ำในแบบสอบถามย่อย" ดังนั้นอาจเป็นการกำกับดูแลที่EXCEPT
ได้รับอนุญาตในกรณีนี้
เพิ่มเติม:
Microsoft ได้ตอบกลับการเชื่อมต่อข้อเสนอแนะของฉันเป็นด้านล่าง
แจ็คเดาถูกต้อง: นี่น่าจะเป็นข้อผิดพลาดทางไวยากรณ์ การอ้างอิงแบบเรียกซ้ำไม่ควรได้รับอนุญาตในEXCEPT
ข้อ เราวางแผนที่จะแก้ไขข้อผิดพลาดนี้ในการเปิดตัวบริการ ในระหว่างนี้ฉันขอแนะนำให้หลีกเลี่ยงการอ้างอิงซ้ำในส่วนEXCEPT
คำสั่ง
ในการ จำกัด การสอบถามซ้ำEXCEPT
เราปฏิบัติตามมาตรฐาน ANSI SQL ซึ่งรวมถึงข้อ จำกัด นี้นับตั้งแต่มีการแนะนำการสอบถามซ้ำ (ในปี 1999 ฉันเชื่อว่า) ไม่มีข้อตกลงอย่างกว้างขวางเกี่ยวกับสิ่งที่ความหมายควรใช้เพื่อเรียกซ้ำEXCEPT
(เรียกอีกอย่างว่า "การปฏิเสธแบบไม่มีการกำหนด") ในภาษาที่ประกาศเช่น SQL นอกจากนี้ยังยากที่จะใช้ความหมายดังกล่าวได้อย่างมีประสิทธิภาพ (สำหรับฐานข้อมูลที่มีขนาดพอสมควร) ในระบบ RDBMS
และดูเหมือนว่าการใช้งานในท้ายที่สุดนั้นถูกสร้างขึ้นในปี 2014 สำหรับฐานข้อมูลที่มีระดับความเข้ากันได้ตั้งแต่ 120 ขึ้นไป
การอ้างอิงแบบเรียกซ้ำในส่วนข้อยกเว้นสร้างข้อผิดพลาดตามมาตรฐาน ANSI SQL