สรุป
ไม่มีเหตุผลเชิงตรรกะที่ไม่สามารถทำได้ แต่ประโยชน์มีน้อยและมีข้อผิดพลาดบางอย่างที่อาจไม่ชัดเจนในทันที
ผลการวิจัย
ฉันค้นคว้าและพบข้อมูลที่ดี ต่อไปนี้เป็นคำพูดโดยตรงจากแหล่งข้อมูลหลักที่เชื่อถือได้ (ที่ประสงค์จะไม่เปิดเผยตัวตน) ที่ 2012-08-09 17:49 GMT:
เมื่อ SQL ถูกคิดค้นครั้งแรกไม่มีนามแฝงในส่วนคำสั่ง SELECT นี่เป็นข้อบกพร่องที่ร้ายแรงซึ่งแก้ไขเมื่อภาษานั้นได้มาตรฐานโดย ANSI ในปี 1986
ภาษานั้นมีวัตถุประสงค์เพื่อ "ไม่ใช่ขั้นตอน" - กล่าวอีกนัยหนึ่งเพื่ออธิบายข้อมูลที่คุณต้องการโดยไม่ระบุวิธีการค้นหา ดังนั้นเท่าที่ฉันรู้ไม่มีเหตุผลว่าทำไมการใช้ SQL ไม่สามารถแยกแบบสอบถามทั้งหมดก่อนที่จะประมวลผลและอนุญาตให้มีการกำหนดนามแฝงทุกที่และใช้ทุกที่ ตัวอย่างเช่นฉันไม่เห็นเหตุผลใด ๆ ที่ทำให้การสืบค้นต่อไปนี้ไม่ถูกต้อง:
select name, salary + bonus as pay
from employee
where pay > 100000
แม้ว่าฉันคิดว่านี่เป็นคำถามที่สมเหตุสมผล แต่ระบบที่ใช้ SQL บางระบบอาจมีข้อ จำกัด ในการใช้ชื่อแทนด้วยเหตุผลบางประการที่เกี่ยวข้องกับการใช้งาน ฉันไม่แปลกใจที่ได้ยินว่า SQL Server ทำเช่นนี้
ฉันสนใจที่จะทำการวิจัยเพิ่มเติมเกี่ยวกับมาตรฐาน SQL-86 และทำไม DBMS สมัยใหม่จึงไม่สนับสนุนการใช้ชื่อแทน แต่ยังไม่มีเวลาที่จะไปไกล สำหรับผู้เริ่มฉันไม่รู้ว่าจะได้รับเอกสารหรือวิธีการตรวจสอบว่าใครทำขึ้นคณะกรรมการ ใครช่วยได้บ้าง ฉันต้องการทราบเพิ่มเติมเกี่ยวกับผลิตภัณฑ์ Sybase ดั้งเดิมที่ SQL Server มาจาก
จากการวิจัยนี้และความคิดเพิ่มเติมฉันสงสัยว่าการใช้นามแฝงในส่วนอื่น ๆ ในขณะที่เป็นไปได้ค่อนข้างไม่เคยมีความสำคัญสูงสำหรับผู้ผลิต DBMS เมื่อเทียบกับคุณสมบัติภาษาอื่น ๆ เนื่องจากมันไม่ได้เป็นอุปสรรคมากนักการทำงานอย่างง่าย ๆ โดยผู้เขียนแบบสอบถามการใช้ความพยายามมากกว่าความก้าวหน้าอื่น ๆ จึงไม่เหมาะสม นอกจากนี้มันจะเป็นกรรมสิทธิ์เนื่องจากเห็นได้ชัดว่าไม่ได้เป็นส่วนหนึ่งของมาตรฐาน SQL (แม้ว่าฉันจะรอดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้อย่างแน่นอน) และจะเป็นการปรับปรุงเล็กน้อย โดยการเปรียบเทียบCROSS APPLY
(ซึ่งจริงๆแล้วไม่มีอะไรมากไปกว่าตารางที่ได้รับอนุญาตให้อ้างอิงจากภายนอก) เป็นการเปลี่ยนแปลงครั้งใหญ่ในขณะที่กรรมสิทธิ์มีพลังการแสดงออกที่เหลือเชื่อไม่สามารถทำได้อย่างง่ายดายในรูปแบบอื่น
ปัญหาเกี่ยวกับการใช้นามแฝงทุกที่
หากคุณอนุญาตให้เลือกรายการไว้ในส่วนคำสั่ง WHERE คุณจะไม่สามารถระเบิดความซับซ้อนของการสืบค้นได้ (และทำให้ความซับซ้อนในการค้นหาแผนการดำเนินการที่ดี) เป็นไปได้ที่จะเกิดสิ่งที่ไร้เหตุผลอย่างสมบูรณ์ ลอง:
SELECT X + 5 Y FROM MyTable WHERE Y = X
จะเกิดอะไรขึ้นถ้า MyTable มีคอลัมน์ Y อยู่แล้วส่วนไหนคือ WHERE clause ที่อ้างถึง? ทางออกคือการใช้ CTE หรือตารางที่ได้รับซึ่งโดยส่วนใหญ่แล้วจะไม่เสียค่าใช้จ่ายเพิ่มเติม แต่ได้ผลลัพธ์สุดท้ายที่เหมือนกัน CTEs และตารางที่ได้รับมาอย่างน้อยบังคับใช้การแก้ปัญหาความกำกวมโดยอนุญาตให้ใช้นามแฝงเพียงครั้งเดียว
นอกจากนี้การไม่ใช้นามแฝงในส่วนคำสั่ง FROM จะทำให้รู้สึกเด่นชัด คุณทำสิ่งนี้ไม่ได้:
SELECT
T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
FROM
Table1 T
INNER JOIN Table2 T2
ON T2.ID = CalcID
INNER JOIN Table3 T3
ON T2.ID = T3.ID
นั่นคือการอ้างอิงแบบวงกลม (ในแง่ที่ว่า T2 จะแอบหมายถึงค่าจาก T3 ก่อนตารางที่ได้รับการนำเสนอในเข้าร่วมรายการ) และยี้ยากที่จะเห็น แล้วอันนี้ละ:
INSERT dbo.FinalTransaction
SELECT
newid() FinalTransactionGUID,
'GUID is: ' + Convert(varchar(50), FinalTransactionGUID) TextGUID,
T.*
FROM
dbo.MyTable T
คุณต้องการวางเดิมพันเท่าไหร่ที่ฟังก์ชัน newid () จะถูกนำไปใส่ในแผนปฏิบัติการสองครั้งโดยสิ้นเชิงทำให้คอลัมน์ทั้งสองแสดงค่าต่างกันโดยไม่คาดคิด? สิ่งที่เกี่ยวกับเมื่อแบบสอบถามข้างต้นจะใช้ระดับ N ลึกใน CTEs หรือตารางที่ได้รับ ฉันรับประกันได้ว่าปัญหาจะเลวร้ายยิ่งกว่าที่คุณสามารถจินตนาการ นอกจากนี้แล้วปัญหาความไม่สอดคล้องกันอย่างจริงจังเกี่ยวกับเมื่อสิ่งที่ได้รับการประเมินเพียงครั้งเดียวหรือสิ่งที่จุดในแผนแบบสอบถามและไมโครซอฟท์ได้กล่าวว่าจะไม่แก้ไขบางส่วนของพวกเขาเพราะพวกเขาจะแสดงพีชคณิตแบบสอบถามอย่างถูกต้อง - หากได้รับผลลัพธ์ที่ไม่คาดคิดแบ่งแบบสอบถามออกเป็นส่วน การอนุญาตให้มีการอ้างอิงแบบโยงโซ่การตรวจสอบการอ้างอิงแบบวนผ่านโซ่ที่อาจยาวมากซึ่งเป็นปัญหาที่ค่อนข้างยุ่งยาก แนะนำการขนานและคุณมีฝันร้ายในการสร้าง
หมายเหตุ: การใช้นามแฝงใน WHERE หรือ GROUP BY จะไม่สร้างความแตกต่างให้กับปัญหาของฟังก์ชั่นเช่น newid () หรือ rand ()
วิธี SQL Server เพื่อสร้างนิพจน์ที่ใช้ซ้ำได้
CROSS APPLY / OUTER APPLY เป็นวิธีหนึ่งใน SQL Server ในการสร้างนิพจน์ที่สามารถใช้ที่ใดก็ได้ในแบบสอบถาม (ไม่ใช่ก่อนหน้าใน FROM clause):
SELECT
X.CalcID
FROM
Table1 T
INNER JOIN Table3 T3
ON T.ID = T3.ID
CROSS APPLY (
SELECT
T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
) X
INNER JOIN Table2 T2
ON T2.ID = X.CalcID
สิ่งนี้ทำสองสิ่ง:
- ทำให้นิพจน์ทั้งหมดใน CROSS ใช้รับ "namespace" (นามแฝงของตารางที่นี่ X) และไม่ซ้ำกันภายในเนมสเปซนั้น
- ทำให้ชัดเจนทุกที่ไม่เพียง แต่ที่ CalcID มาจาก X แต่ยังทำให้เห็นได้ชัดว่าทำไมคุณไม่สามารถใช้อะไรจาก X เมื่อเข้าร่วมตารางที่ T1 และ T3 เพราะ X ยังไม่ได้เปิดตัว
จริง ๆ แล้วฉันชอบ CROSS มากกว่า มันได้กลายเป็นเพื่อนที่ซื่อสัตย์ของฉันและฉันใช้มันตลอดเวลา ต้องการ UNPIVOT บางส่วน (ซึ่งต้องใช้ PIVOT / UNPIVOT หรือ UNPIVOT / PIVOT โดยใช้ไวยากรณ์ดั้งเดิม) เสร็จสิ้นด้วย CROSS APPLY ต้องการค่าที่คำนวณได้ซึ่งจะนำมาใช้ซ้ำหลายครั้งหรือไม่ เสร็จสิ้น ต้องการบังคับใช้คำสั่งดำเนินการอย่างเข้มงวดสำหรับการโทรผ่านเซิร์ฟเวอร์ที่เชื่อมโยงหรือไม่ เสร็จแล้วด้วยการปรับปรุงความเร็วกรีดร้อง ต้องการแบ่งแถวประเภทเดียวเป็น 2 แถวหรือมีเงื่อนไขเพิ่มเติมหรือไม่ เสร็จสิ้น
ดังนั้นอย่างน้อยที่สุดใน DBMS SQL Server 2005 และสูงกว่าคุณไม่มีสาเหตุของการร้องเรียนอีกต่อไป: CROSS APPLY เป็นวิธีที่คุณแห้งในแบบที่คุณต้องการ