はじめに
業務でSQLを書いていると
外部結合をしたい場面に出くわすことがよくあります。
正規化されたテーブルは、
だいたいトランザクションにコードだけが入っていて、
その名称を取得しようとする場合、マスタと外部結合しますよね。
例えばコンビニのレシート
コンビニレシートの明細がトランザクションとしたとき、商品コードが明細に登録され、
商品マスタが別に存在するという状況をイメージして下さい。
そして、商品にグループがあって、
あるグループの商品だけ名称を取得したいときは、、条件を付けますね。
(いい例が思いつかず、変な例ですいません。m(_ _)m)
本題
ここで本題です。
条件の位置によって、外部結合のつもりが内部結合になるという事象にぶつかります。
いや、知ってますよ~。
という方はここで読むのをやめてもらってOKです。
え!? ホントに?
という方だけ続きを読んでください。
それでは、具体的な例を見ていきましょう。
前提
先にコンビニレシートを例にしたのを引継ぎ、そのイメージで進めます。
コンビニレシート:3商品買った。そのうち、1つは「飲み物」とします。
※あえて、飲み物だけ商品名を表示しないとします。
(また、変な例ですw)
SELECT文
ざっくりですが、下記のようなイメージのSQLで取得できます。
明細は、3行取得されます。
select
明細.商品コード
商品マスタ.商品名
商品マスタ.商品価格
from
明細
left outer join 商品マスタ
on (
明細.商品コード = 商品マスタ.商品コード
and 商品マスタ.グループ <> ’飲み物’
)
where
明細.お会計シーケンス = ’いまのお会計のユニークNo’
order by
明細.バーコードを読み取った順
SELECT文(条件の位置を変えてみる)
上記のSQLの「飲み物」以外という条件をwhereの方に持って行きます。
明細は2行取得され、なんと「飲み物」の行が消えます。
select
明細.商品コード
商品マスタ.商品名
商品マスタ.商品価格
from
明細
left outer join 商品マスタ
on (
明細.商品コード = 商品マスタ.商品コード
- and 商品マスタ.グループ <> ’飲み物’ --★条件を移動(削除する)
)
where
明細.お会計シーケンス = ’いまのお会計のユニークNo’
+ and 商品マスタ.グループ <> ’飲み物’ --★ここに移動(追加する)
order by
明細.バーコードを読み取った順
なぜ「飲み物」の行が消えたのか?
これは、どの段階で条件が適用されるのかが理解できれば、
簡単にわかるはずです。
-
from句
from句に条件があるときを見てみます。
「明細」に「left outer join 商品マスタ」を外部結合する。
その時の条件として、on句に「商品マスタ.グループ <> ’飲み物’」の条件があるとき、
商品マスタを「飲み物以外」に絞った結果と「明細」を外部結合します。
(商品マスタから「飲み物」がなくなった状態で、外部結合しているイメージ) -
Where句
Where句に「商品マスタ.グループ <> ’飲み物’」の条件があるときを見てみます。
明細と商品マスタを外部結合した「結果」のデータに対して、条件を付けている事になります。
(明細と商品マスタを外部結合した時点では、「飲み物」の行がある。)
よって、外部結合したのに、
内部結合したかのような結果が取れてしまいます。
勘のいい方は、もうわかった!と思っていることでしょう。
厳密には記述通りに動作していていますから、
「本題」で書いた「内部結合になる」の記述は間違いですね。ごめんなさい。
まとめ
今回は、いつ適用されるのか?が焦点でした。
group by
や、order by
などの句がいつ適用されるのかを意識すると、思わぬ不具合を回避できます。
十分に分かっている方も一度見直してみたら、新たな発見があるかも知れません。