17

外部結合と内部結合を組み合わせるときにテーブルの順序が重要なのはなぜですか? 以下はpostgresで失敗します:

SELECT grp.number AS number,     
       tags.value AS tag   
FROM groups grp,
     insrel archiverel  
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   
WHERE archiverel.snumber = 11128188 AND    
      archiverel.dnumber = grp.number 

結果:

ERROR:  invalid reference to FROM-clause entry for table "grp" LINE 5: LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.d... 
^ HINT:  There is an entry for table "grp", but it cannot be referenced from this part of the query.

FROM でグループを逆にすると、すべてが機能します。

SELECT  grp.number AS number,     
        tags.value AS tag   
FROM    insrel archiverel,
        groups grp
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   
WHERE   archiverel.snumber = 11128188 AND    
        archiverel.dnumber = grp.number 
4

5 に答える 5

20

これは、演算子の優先順位の問題と考えることができると思います。

これを書くとき:

FROM groups grp,
     insrel archiverel  
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   

パーサーによって次のように解釈されると思います。

FROM groups grp,
(
  (
     insrel archiverel  
     LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
  )
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber
)

その場合、最も内側の結合で "grp" はバインドされていません。

「groups」と「insrel」で行を逆にすると、最内結合が「groups」と「ownrel」に適用されるので動作します。

おそらくこれもうまくいくでしょう:

    FROM groups grp
         JOIN insrel archiverel  ON archiverel.dnumber = grp.number
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
    LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188
于 2008-10-09T13:39:29.107 に答える
19

誰もこれを完全に釘付けにしたり、うまく説明したりしているとは思いません。「古いスタイル」(シータ) と「新しいスタイル」(ANSI) の結合を組み合わせていますが、予想外の方法でグループ化されていると強く疑われます。このように見てください:

SELECT * FROM a, b JOIN c ON a.x = c.x

と言っているような

SELECT * FROM a, (b JOIN c on a.x = c.x)

ここで、角かっこで囲まれたものは、「a」に対するシータ結合で結合される、1 つの仮想テーブルにマージされた一連のテーブルを表します。明らかに、「a」テーブルは後で結合されるだけなので、結合の一部にすることはできません。それを逆にすると、あなたはやっています

SELECT * FROM b, (a JOIN c on a.x = c.x)

これは完全に理解でき、とても素晴らしいです。ANSI結合構文をすべて使用していない理由はわかりませんが、少し奇妙に思えます(そして、それを維持しなければならない人にとっては残酷です!)

于 2008-10-09T13:39:04.350 に答える
5

最初の 1 つの grp は、ON 句が属する結合の一部ではないためです。

于 2008-10-09T13:06:32.887 に答える
4

バグなのか仕様によるものなのか、何が原因なのかはわかりませんが、いずれかの形式の結合に固執すれば問題なく動作するはずです。

SELECT grp.number AS number,     
       tags.value AS tag   
FROM groups grp
JOIN insrel archiverel ON archiverel.dnumber = grp.number
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   
WHERE archiverel.snumber = 11128188

動作が設計によるものであるかどうか、もっと知りたいです。

于 2008-10-09T13:11:02.517 に答える
2

内部結合の場合、テーブルの順序は重要ではありません。

アウタージョインの場合はそうです。 指定された側のテーブルのすべての行(LEFTまたはRIGHT結合)が含まれ、結合基準に一致する行のみが反対側のテーブルから含まれます。

OUTER JOINSはすべての行を片側から保持するため、(一般に)結果セットを増やすと言われています。INNER JOINSは、一致する場合にのみ両側からの行を保持するため、(一般に)結果セットを減らすと言われています。したがって、通常は、外部結合の前に内部結合を実行する必要があります(可能な場合)。

あなたの場合、それはほぼ間違いなく邪悪なA、B構文の結果です。

于 2008-10-09T13:22:36.643 に答える