ON句の位置は実際にはどういう意味ですか?


23

通常のJOIN ... ON ...構文はよく知られています。ただし、対応するON句とは別に句を配置することもできJOINます。これは、実際にはめったに見られないものであり、チュートリアルにはありません。また、これが可能であると言及しているWebリソースも見つかりませんでした。

ここで遊ぶスクリプトは次のとおりです。

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句のこれらの異常な位置があります。

このスクリプトは必ずしもあまり意味がありません。意味のあるシナリオを考え出すのは私にとって困難でした。

これらの異常な構文パターンはどういう意味ですか?これはどのように定義されていますか?2つのON句のすべての位置と順序が許可されているわけではないことに気付きました。これを管理する規則は何ですか?

また、このようなクエリを書くことは良い考えですか?

回答:


32

あなたが見ればFROM句の構文図、あなたは1つだけの場所があることがわかります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によってカバーされています。

... JOIN条件は、テーブルの順序との明白な関係に従う必要があります。つまり、テーブル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条件が既に参照および解決したテーブル名のみを参照できます。

しかし、この記事には不正確な点がいくつかあります。LuborKollarのフォローアップレターも参照してください。


マーティンのおかげで、この答えはとても役に立ちました。ただし、正式な文法についての彼の論点が、問題を完全に理解するのに役立ったので、私はもう一方を受け入れます。特に、「破滅的な関係」は間違った考えのようです。それはリストであり、逆のリストではありません。mustaccioは、Itziksの解釈が正しくない理由を理解するためのフレームワークを提供しました。
boot4life
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.