Apa yang sebenarnya dimaksud dengan posisi klausa ON?

23

JOIN ... ON ...Sintaks normal sudah dikenal. Tetapi juga dimungkinkan untuk menempatkan ONklausa secara terpisah dari klausa JOINyang terkait. Ini adalah sesuatu yang jarang terlihat dalam praktek, tidak ditemukan dalam tutorial dan saya belum menemukan setiap sumber daya web yang bahkan menyebutkan bahwa ini adalah mungkin.

Berikut ini adalah skrip untuk bermain-main:

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 terlihat normal. q2 dan q3 memiliki posisi ONklausa yang tidak biasa ini .

Skrip ini tidak selalu masuk akal. Sulit bagiku untuk menyusun skenario yang bermakna.

Jadi apa arti dari pola sintaksis yang tidak biasa ini? Bagaimana ini didefinisikan? Saya perhatikan bahwa tidak semua posisi dan pemesanan untuk kedua ONklausa diperbolehkan. Apa aturan yang mengatur ini?

Juga apakah pernah ada ide bagus untuk menulis pertanyaan seperti ini?

boot4life
sumber

Jawaban:

32

Jika Anda melihat FROMdiagram sintaks klausa, Anda akan melihat bahwa hanya ada satu tempat untuk ONklausa:

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

Yang Anda anggap membingungkan adalah rekursi sederhana, karena <table_source>di <joined_table> di atas bisa jadi lain <joined_table>:

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

Untuk menghindari kebingungan, Anda harus menggunakan tanda kurung dalam kasus yang tidak jelas (seperti contoh Anda) untuk memisahkan secara visual <table_sources>; mereka tidak diperlukan untuk parser permintaan tetapi bermanfaat bagi manusia.

mustaccio
sumber
33

Ini menentukan tabel logis yang terlibat dalam bergabung.

Dengan contoh sederhana

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 

#widgets1dibiarkan luar bergabung #widgets2- hasil yang membentuk tabel virtual yang bergabung batin #widgetProperties. Predikatnya w2.WidgetID = wp.WidgetIDakan berarti bahwa setiap baris yang diperpanjang nol dari gabungan luar awal disaring, secara efektif membuat semua gabungan batin bergabung.

Ini berbeda dari 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

#widgets2adalah batin bergabung #widgetProperties. Tabel virtual yang dihasilkan dari gabungan itu adalah kemudian tabel kanan di Kiri Luar Gabung#widgets1

Hasil yang sama dapat dicapai dengan menggunakan tabel turunan atau Common Table Expression ...

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 

... Atau Anda dapat memesan ulang tabel virtual dan menggunakannya sebagai RIGHT JOINgantinya.

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 

Ini dicakup oleh Itzik Ben Gan di sini

... kondisi BERGABUNG harus mengikuti hubungan chiastic ke urutan tabel. Yaitu, jika Anda menentukan tabel T1, T2, T3, dan T4 dalam urutan itu dan kondisi GABUNGAN cocok dengan T1 dengan T2, T2 dengan T3, dan T3 dengan T4, Anda harus menentukan kondisi GABUNGAN dalam urutan yang berlawanan dengan urutan tabel , seperti ini:

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 

Untuk melihat teknik bergabung ini dengan cara yang berbeda, kondisi JOIN yang diberikan hanya dapat merujuk ke nama tabel tepat di atasnya atau nama tabel yang sebelumnya telah bergabung dan diselesaikan dengan kondisi yang digabung.

tetapi artikel tersebut memiliki sejumlah ketidakakuratan, lihat juga surat tindak lanjut dari Lubor Kollar .

Martin Smith
sumber
Terima kasih Martin, jawaban ini sangat membantu. Saya akan menerima yang lain, karena poinnya tentang tata bahasa formal adalah apa yang membantu saya sepenuhnya memahami masalah ini. Khususnya "hubungan chiastik" tampaknya merupakan gagasan yang salah. Itu adalah pohon, bukan daftar plus daftar terbalik. mustaccio menyediakan kerangka kerja untuk memahami mengapa interpretasi Itzik tidak tepat.
boot4life