最近、仕事では複雑なSQLばっかり書いています。
ただ、今関わっているプロジェクトでは上から設計書を渡されてそれをコードとして書くのですが、SQL部分はほとんどそのままで、違うのはテーブル名やフィールド名が日本語になっているぐらいという感じです(場合によっては、効率が悪かったり、ムダにSQLを分けているなと思うと、こちらで書いて後から設計書に反映してもらうこともあります。変更が大きかったりすると嫌がられてるのが伝わってきます)。
そんな中で出てきたコードが下記のようなコード。自分も書いてるときは何も思わずにそのまま書いてしまっていました。
SELECT table1.id, table3.field FROM table1 LEFT JOIN table2 ON table1.subid = table2.id INNER JOIN table3 ON table2.subid = table3.id
問題です。table1のsubid(ここでは1とする)に対応するtable2のidが見つからない場合、結果はどうなるでしょう。
答えは、
id | field |
---|---|
1 | null |
とはなりません。
なぜなら、table1のsubidに対応するtable2がないのだから、内部結合しているtable2に対応するtable3もないから。で、外部結合だと対応する値が無くても出力しますが、内部結合だと対応する値が無いと出力しないので、結果、出力しないことになります。
なので、上記のSQLはtable3の結合も内部結合として、
SELECT table1.id, table3.field FROM table1 LEFT JOIN table2 ON table1.subid = table2.id LEFT JOIN table3 ON table2.subid = table3.id
とするのが正解なはずです。多分、table1にあってtable2に対応する値が無いことはあるけれど、table2にあって対応する値がtable3に無いことは無い(絶対にある)ので、こういうSQLを作ってしまったんだと思います。
ところで、今のプロジェクトで使っているDBMSはDB2の10.1なのですが、上記のようなSQLにおいて、なぜかWHERE句にANDを追加すると値が出力されるのだけど、無いと出力されないという摩訶不思議な現象が発生しました(ANDを使って条件を追加すると、通常は結果が変わらないか少なくなるはず)。
いろいろ調べてみると、上記のように結合部分がおかしかったので修正したら直りはしたのですが、なぜこんな現象がでたのかは謎です(条件の部分に関しては、上記の結合箇所は全く関係無かったし)。DB2のバグっぽいのだけど、そういう現象って報告されてたりするのだろうか。条件によってでたりでなかったりしたので、再現方法はわからないのだけど。
コメント