ทำไม CTE ควรเริ่มต้นด้วยเซมิโคลอน


14

ฉันแค่ดูโพสต์ในStackOverflowที่ Aaron Bertrand เสนอให้ใช้ CTE แทนตารางตัวเลขซึ่งเป็นวิธีที่ยอดเยี่ยมในการปฏิบัติงานในมือ คำถามของฉันคือทำไมบรรทัดแรกของ CTE เริ่มต้นด้วยเซมิโคลอน

;WITH n AS (SELECT TOP (10000) n FROM 
  (SELECT n = ROW_NUMBER() OVER
    (ORDER BY s1.[object_id])
    FROM sys.all_objects AS s1
    CROSS JOIN sys.all_objects AS s2
  ) AS x ORDER BY n
)
SELECT n FROM n ORDER BY n; -- look ma, no gaps!

นี่คือเพื่อให้แน่ใจว่าคำสั่ง WITH จะไม่ถูกวิเคราะห์คำก่อนหน้าSELECTหรือบางอย่าง? ฉันไม่เห็นอะไรใน SQL Server 2005 BOL เกี่ยวกับการใช้เซมิโคลอนก่อนหน้า WITH


คำตอบ:


26

ฉันมักจะทำมันเมื่อโพสต์ที่นี่หรือใน StackOverflow เพราะสำหรับWITH- เนื่องจากคำหลักมีมากเกินไป - คำสั่งก่อนหน้าต้องมีเซมิโคลอนสิ้นสุด หากฉันวางตัวอย่างโค้ดที่ใช้ CTE ผู้ใช้บางรายจะวางลงในรหัสที่มีอยู่ของพวกเขาและคำสั่งก่อนหน้าจะไม่มีเซมิโคลอน ดังนั้นรหัสแบ่งและฉันได้รับข้อร้องเรียนเช่น:

รหัสของคุณเสีย! ฉันได้รับข้อความแสดงข้อผิดพลาด:

Incorrect syntax near 'WITH'...

ในขณะที่ฉันอยากจะเชื่อว่าคนจะดีขึ้นเกี่ยวกับการยกเลิกคำพูดของพวกเขาด้วยเซมิโคลอนแต่ฉันควรกำจัดเสียงรบกวนล่วงหน้าและรวมไว้ด้วยเสมอ บางคนไม่ชอบ <shrug />แต่ คุณสามารถรวมเซมิโคลอนจำนวนมากก่อนหรือหลังคำสั่งที่ถูกต้องตามที่คุณต้องการ สิ่งนี้ใช้ได้:

;;;;SELECT 1;;;;;;;;;;;;SELECT 2;;;;;;;;SELECT 3;;;;;

ดังนั้นจึงไม่มีอันตรายใด ๆ ในการมีเซมิโคลอนพิเศษก่อนหน้าคำสั่งที่นิยามไว้ใช้ การทำเช่นนั้นปลอดภัยกว่าแม้ว่าจะไม่สวยก็ตาม

จะต้องมี worded อย่างแปลกประหลาดเพื่อให้ได้จุดข้าม แต่ "ไม่สิ้นสุดคำสั่งที่ถูกต้องกับเซมิโคลอน" ถูกคัดค้านจริงตั้งแต่ SQL Server 2008 ดังนั้นตามที่ฉันอธิบายในโพสต์บล็อกฉันลิงก์ไปด้านบนแม้ในกรณีที่ ไม่จำเป็นต้องข้ามข้อผิดพลาดควรใช้ทุกที่ที่ถูกต้อง คุณสามารถดูได้ที่นี่:

http://msdn.microsoft.com/en-us/library/ms143729.aspx

(ค้นหาหน้าสุดท้ายสำหรับ "เซมิโคลอน")

แน่นอนว่ามันจะไม่ใช่ SQL Server ถ้าไม่มีข้อยกเว้น ลองสิ่งนี้:

BEGIN TRY;
  SELECT 1/1;
END TRY;
BEGIN CATCH;
  SELECT 1/1;
END CATCH;

มันไม่ได้เป็นข้อยกเว้นเพียงอย่างเดียวของกฎ แต่เป็นสิ่งที่ฉันพบว่าไม่ได้ใช้งานง่ายที่สุด


1
ในปี 2012 ฉันยังได้รับข้อความแสดงข้อผิดพลาดเหมือนเดิม แต่เป็นเพราะเซมิโคลอนหลังEND TRY: i.stack.imgur.com/rc6dw.png - หากฉันลบเซมิโคลอนนั้นออกทุกอย่างทำงานได้
Aaron Bertrand

ฉันคิดว่าคุณไม่สามารถใส่อัฒภาคก่อนเพียงเพราะมันเป็นส่วนหนึ่งของงบสารประกอบเดียวนำมาใช้กับBEGIN CATCH BEGIN TRYมันเป็นเช่นเดียวกับการวางอัฒภาคก่อนที่งบIF ELSE
Andriy M

@AndriyM ฉันได้รับการสนทนารายละเอียดเพิ่มเติมเกี่ยวกับกฎที่นี่ ฉันพูดถึงเรื่องนี้เพราะมันเป็นเรื่องน่าประหลาดใจสำหรับทุกคนที่เจอมันไม่ใช่เพราะฉันไม่เข้าใจเหตุผล :-)
Aaron Bertrand

10

นี่คือเพื่อให้แน่ใจว่าจะไม่รวมอยู่ในงบก่อนหน้าใด ๆ เนื่องจากWITHสามารถตอบสนองวัตถุประสงค์ที่หลากหลายใน T-SQL

ถ้ามันเป็นคำสั่งแรกในแบตช์ฉันไม่คิดว่าคุณต้องการมัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.