同じ結果を生成する複数の結合の2つのバージョンがあります。 5つのテーブルは次のとおりです。
customers ← sales ← saleitems → paintings → artists
矢印は(うまくいけば)テーブル間の関係を示しています。
各テーブルにはid
という主キーがあり、内部テーブルには[othertable]id
という別のテーブルへの外部キーがあります。
最初のバージョンは、上記の順序でリストされたテーブルとのクラシック結合です
SELECT
c.id, c.givenname, c.familyname,
a.givenname, a.familyname
FROM
customers c
JOIN sales s ON c.id=s.customerid
JOIN saleitems si ON s.id=si.saleid
JOIN paintings p ON si.paintingid=p.id
JOIN artists a ON p.artistid=a.id
;
2番目のバージョンは、すべてのJOIN
句を最初にjaし、ON
句を逆順にします。
SELECT
c.id, c.givenname, c.familyname,
a.givenname, a.familyname
FROM
customers c
JOIN sales s
JOIN saleitems si
JOIN paintings p
JOIN artists a
ON p.artistid=a.id
ON si.paintingid=p.id
ON s.id=si.saleid
ON c.id=s.customerid
;
わかりました。動作しますが、2番目のバージョンの動作を説明できる人はいますか? ON
句の順序をJOIN
句の逆にする必要があるのはなぜですか? JOIN
またはON
句をランダムに並べることはできますか?
Microsoft SQLとPostgreSQLでこれをテストしました。
それらをランダム化することはできません。順序は重要です。結合の間にいくつかの括弧を追加すると、より明確に見えるかもしれません。
SELECT
c.id
FROM
customers c
JOIN (sales s JOIN saleitems si ON s.id = si.saleid)
ON c.id = s.customerid
このクエリが実行していることは、最初にsales
をsaleitems
に結合し、次にその結果をcustomers
に結合しています。括弧結合内のcustomers
列はアクセスできないため参照できません。
SELECT
c.id
FROM
customers c
JOIN (sales s JOIN saleitems si ON s.id = si.saleid
AND c.id = c.customerid) -- What is c.customerid here??
メッセージ4104、レベル16、状態1、行6マルチパート識別子「s.customerid」をバインドできませんでした。
あなたが私に尋ねるなら、私はクエリを書く最初の方法にこだわるでしょう、それはほとんどのプログラマにとってその方法ではるかに明確です。
ほとんどの場合、JOIN構文では、JOINとONの両方が存在する必要があります(ONが違いを生じさせないCROSS JOINなどの特定の状況を除く)。これをBEGIN..END
ステートメント-END
ステートメントでなければなりません。前の最も近いBEGIN
に関連しています
BEGIN -- block 1
BEGIN -- block 2
--
END -- end block 2
END -- end block 1
そのため、ON句を逆の順序で配置すると機能しました。ただし、どの条件がどのテーブルに関連しているかを判断するのに時間がかかるため、これは良い方法ではありません。特に途中でインデント/フォーマットを緩めた場合。
さらに、2番目と次のすべてのJOINSの追加のインデントは不要です。通常、JOIN
句の順序は重要ではありません(オプティマイザに強制するクエリヒントを使用しない限り)。
私は個人的には、以下のようにすっきりすると思います(+ INNER JOINを明示的に示し、+関心のある「ファクト」テーブルから結合をアレンジします。他のテーブルは、取得しているファクトの説明です。重要であればオプションで、各列を別々の行に配置します-重要でない場合、通常は1行に配置します)。しかし、再び、これは個別のコーディングスタイルのことです。
SELECT
c.id, c.givenname, c.familyname,
a.givenname, a.familyname
FROM
saleitems si
INNER JOIN sales s ON si.SaleId = s.Id
INNER JOIN customers c ON s.CustomerId = c.Id
INNER JOIN paintings p ON si.PaintingId = p.Id
INNER JOIN artists a ON p.ArtistId = a.Id