ตำแหน่งของอนุประโยค ON หมายถึงอะไรจริง ๆ ?


23

JOIN ... ON ...ไวยากรณ์ปกติเป็นที่รู้จักกันดี แต่มันก็เป็นไปได้ที่จะวางตำแหน่งONประโยคแยกจากJOINที่มันสอดคล้องกับ นี่คือสิ่งที่ไม่ค่อยเห็นในทางปฏิบัติไม่พบในบทช่วยสอนและฉันไม่ได้พบแหล่งข้อมูลบนเว็บใด ๆที่แม้แต่กล่าวถึงสิ่งนี้ว่าเป็นไปได้

นี่คือสคริปต์ที่จะเล่นกับ:

SELECT *
INTO #widgets1
FROM (VALUES (1), (2), (3)) x(WidgetID)


SELECT *
INTO #widgets2
FROM (VALUES (1, 'SomeValue1'), (2, 'SomeValue2'), (3, 'SomeValue3')) x(WidgetID, SomeValue)

SELECT *
INTO #widgetProperties
FROM (VALUES
    (1, 'a'), (1, 'b'),
    (2, 'a'), (2, 'b'))
x(WidgetID, PropertyName)


--q1
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN #widgets2 w2 ON w2.WidgetID = w1.WidgetID
LEFT JOIN #widgetProperties wp ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = 'b'
ORDER BY w1.WidgetID


--q2
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN #widgets2 w2 --no ON clause here
JOIN #widgetProperties wp
 ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = 'b'
 ON w2.WidgetID = w1.WidgetID
ORDER BY w1.WidgetID


--q3
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN (
    #widgets2 w2 --no SELECT or FROM here
    JOIN #widgetProperties wp
    ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = 'b')
ON w2.WidgetID = w1.WidgetID
ORDER BY w1.WidgetID

q1 ดูปกติ q2 และ q3 มีตำแหน่งผิดปกติของONประโยคเหล่านี้

สคริปต์นี้ไม่จำเป็นต้องสมเหตุสมผลมากนัก มันยากสำหรับฉันที่จะประดิษฐ์สถานการณ์ที่มีความหมาย

รูปแบบไวยากรณ์ที่ผิดปกติเหล่านี้หมายความว่าอย่างไร สิ่งนี้กำหนดไว้อย่างไร? ฉันสังเกตเห็นว่าไม่ONอนุญาตให้มีตำแหน่งและการสั่งซื้อทั้งหมดสำหรับสองข้อ กฎอะไรที่ควบคุมสิ่งนี้

นอกจากนี้คุณควรเขียนข้อความค้นหาเช่นนี้หรือไม่?

คำตอบ:


32

หากคุณดูที่FROMแผนภาพไวยากรณ์ของข้อคุณจะเห็นว่ามีเพียงที่เดียวสำหรับONข้อ:

<joined_table> ::= 
{
    <table_source> <join_type> <table_source> ON <search_condition> 
    ...
}

สิ่งที่คุณสับสนคือการเรียกซ้ำง่าย ๆ เพราะ<table_source>ใน<joined_table> ด้านบนสามารถเป็นอีกแบบ<joined_table>:

[ FROM { <table_source> } [ ,...n ] ] 
<table_source> ::= 
{
    table_or_view_name ... 
    ...
    | <joined_table> 
    ...
}

หลีกเลี่ยงความสับสนคุณควรใช้วงเล็บในกรณีที่ไม่ชัดเจน (เช่นตัวอย่างของคุณ) เพื่อแยกต่างหากสายตา<table_sources>; ไม่จำเป็นสำหรับตัวแยกวิเคราะห์คิวรี แต่มีประโยชน์สำหรับมนุษย์


33

มันกำหนดตารางตรรกะที่เกี่ยวข้องในการเข้าร่วม

ด้วยตัวอย่างง่ายๆ

SELECT w1.WidgetID,
       w2.SomeValue,
       wp.PropertyName
FROM   #widgets1 w1
       LEFT JOIN #widgets2 w2
         ON w2.WidgetID = w1.WidgetID
       JOIN #widgetProperties wp
         ON w2.WidgetID = wp.WidgetID
            AND wp.PropertyName = 'b'
ORDER  BY w1.WidgetID 

#widgets1เป็นด้านนอกซ้ายเข้าร่วม#widgets2- #widgetPropertiesผลของการที่รูปแบบตารางเสมือนที่อยู่ภายในได้เข้าร่วมกับ เพรดิเคตw2.WidgetID = wp.WidgetIDจะหมายถึงว่าแถวที่ขยายเป็นโมฆะใด ๆ จากการรวมภายนอกเริ่มต้นจะถูกกรองออก

สิ่งนี้แตกต่างจาก q2 ...

SELECT w1.WidgetID,
       w2.SomeValue,
       wp.PropertyName
FROM   #widgets1 w1
       LEFT JOIN #widgets2 w2 --no ON clause here
                 JOIN #widgetProperties wp
                   ON w2.WidgetID = wp.WidgetID
                      AND wp.PropertyName = 'b'
         ON w2.WidgetID = w1.WidgetID
ORDER  BY w1.WidgetID

#widgets2#widgetPropertiesจะเข้าร่วมด้านบน ตารางเสมือนที่เกิดจากการเข้าร่วมนั้นเป็นตารางด้านขวาในการเข้าร่วมด้านนอกด้านซ้ายบน#widgets1

ผลลัพธ์เดียวกันสามารถทำได้โดยใช้ตารางที่ได้รับหรือนิพจน์ตารางทั่วไป ...

WITH VT2
     AS (SELECT w2.WidgetID,
                w2.SomeValue,
                wp.PropertyName
         FROM   #widgets2 w2 
                JOIN #widgetProperties wp
                  ON w2.WidgetID = wp.WidgetID
                     AND wp.PropertyName = 'b')
SELECT w1.WidgetID,
       VT2.SomeValue,
       VT2.PropertyName
FROM   #widgets1 w1
       LEFT JOIN VT2
         ON VT2.WidgetID = w1.WidgetID
ORDER  BY w1.WidgetID 

... หรืออีกวิธีหนึ่งคุณสามารถสั่งซื้อตารางเสมือนใหม่และใช้RIGHT JOINแทน

SELECT w1.WidgetID,
       w2.SomeValue,
       wp.PropertyName
FROM   #widgets2 w2
       INNER JOIN #widgetProperties wp
               ON w2.WidgetID = wp.WidgetID
                  AND wp.PropertyName = 'b'
       RIGHT JOIN #widgets1 w1
               ON w2.WidgetID = w1.WidgetID
ORDER  BY w1.WidgetID 

นี่ถูกปกคลุมด้วย Itzik Ben Gan ที่นี่

... เงื่อนไขการเข้าร่วมจะต้องปฏิบัติตามความสัมพันธ์ที่วุ่นวายกับคำสั่งตาราง นั่นคือถ้าคุณระบุตาราง T1, T2, T3 และ T4 ในลำดับนั้นและเงื่อนไข JOIN ตรงกับ T1 กับ T2, T2 กับ T3 และ T3 กับ T4 คุณต้องระบุเงื่อนไข JOIN ตามลำดับตรงข้ามกับลำดับตาราง , อย่างนี้:

FROM   T1
       <join_type> T2 T2
                  <join_type> T3 T3
                             <join_type> T4
                               ON T4.key = T3.key
                    ON T3.key = T2.key
         ON T2.key = T1.key 

หากต้องการดูเทคนิคการรวมนี้ในวิธีที่แตกต่างกันเงื่อนไข JOIN ที่ระบุสามารถอ้างอิงได้เฉพาะชื่อตารางด้านบนหรือชื่อตารางที่เงื่อนไข JOIN ก่อนหน้านี้ได้อ้างถึงและแก้ไขแล้ว

แต่บทความมีจำนวนของความไม่ถูกต้องดูจดหมายติดตามโดย Lubor Kollarเช่นกัน


ขอบคุณ Martin คำตอบนี้มีประโยชน์มาก ฉันจะยอมรับอีกเรื่องหนึ่งเนื่องจากประเด็นของเขาเกี่ยวกับไวยากรณ์ที่เป็นทางการคือสิ่งที่ช่วยให้ฉันเข้าใจปัญหาได้อย่างเต็มที่ โดยเฉพาะอย่างยิ่ง "ความสัมพันธ์ chiastic" ดูเหมือนจะเป็นความคิดที่ผิด มันเป็นต้นไม้ไม่ใช่รายการบวกกับรายการที่กลับรายการ mustaccio จัดทำกรอบเพื่อทำความเข้าใจว่าทำไมการตีความ Itziks ไม่ถูกต้องนัก
boot4life
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.