SQLを学ぶにあたって最初の関門がGROUP BY句だとすると、その次に関門は副問合せ(サブクエリ)である。
図の通り、副問合せとはカッコを用いて問合せ文が入れ子の形式になったものである。
今回は、この副問合せと相関副問合せについて観てみよう。
・副問合せ
副問合せは主問合せの前に実行され、その実行結果は主にWHERE句の条件に使用される。
数学で、2✖️(4+5)という計算があるとき、カッコ内の4+5が先に計算されるが、それと同じ要領で副問合せを先に処理するのである。
社員番号 | 氏名 | 基本給 | 部署 |
0001 | 川田 | 500,000 | 法人税 |
0002 | 佐藤 | 600,000 | 所得税 |
0003 | 渡辺 | 500,000 | 法人税 |
この表から、社員が2名以上いる部署に所属する社員の氏名を一覧するSELECT文を実行する。
SELECT 氏名
FROM 社員
WHERE 部署 IN (SELECT 部署
FROM 社員
GROUP BY 部署
HAVING COUNT(*)>=2 )
このSELECT文だと、まずカッコ内かろ実行され、その結果に基いて外側が実行されるのである。
列名(この場合は部署)IN(副問合せ)で、列の値が副問合せ結果のいずれかに一致するっということを意味し、それがWHERE句によりその結果に合致する行を選択する。
カッコ内の処理により、行数が2以上ある部署(この場合は法人税)のみ抽出され、その部署のある行が選択され、氏名で射影されて、次の結果を得る。
氏名 |
川田 |
渡辺 |
INではなく、NOT IN にすると一致しない行が選択される。(この場合は所得税)
結果は以下の通り。
氏名 |
佐藤 |
副問合せはWHERE句で行の選択をする際の条件の設定に使われることが多い。
副問合せで指定した表より条件にあう行を選択し、SELECTで列を射影した結果を、INなら合致する行を、NOT INなら合致しない行を選択すし、主問合せのSELECTで射影するわけだ。
・相関副問合せ
副問合せだと、カッコ内のすべての処理終了後にWHERE句の選択が実行されるが、相関副問合せというのは、主問合せの列を副問合せ内で参照していく方法だ。
社員番号 | 氏名 | 基本給 | 部署コード |
0001 | 川田 | 500,000 | HZ |
0002 | 佐藤 | 550,000 | SZ |
0003 | 渡辺 | 450,000 | HZ |
0004 | 木山 | 400,000 | SZ |
部署コード | 部署名 | 部署長社員番号 |
HZ | 法人税 | 0001 |
SZ | 所得税 | 0002 |
これら二つの表を用いて次のSQL文を実行する。
SELECT 氏名
FROM 社員
WHERE EXISTS (SELECT *
FROM 部署
WHERE 部署.部署長社員番号=社員.社員番号
この場合だと、カッコ内から最初に処理されるが、副問合せとは微妙に異なっている。
まずカッコ内の部署表において部署長番号と社員表の社員番号が一致する社員表の行が存在すれば、その行を選択する。(真を返す。存在しないと偽を返す。偽だと抽出対象が無いということになるのだ)
カッコ内の条件を満たす社員表の行が選択されると、
社員番号 | 氏名 | 基本給 | 部署コード |
0001 | 川田 | 500,000 | HZ |
0002 | 佐藤 | 550,000 | SZ |
これに主問合せのSELECT句を射影すると、
氏名 |
川田 |
佐藤 |
結果として抽出されるのは上図である。
なお、EXISTSの代わりに NOT EXISTS を使用するとカッコ内の条件に一致しない行が選択され射影されるわけだから、
氏名 |
渡辺 |
木山 |
が抽出される。
・副問合せと相関副問合せの違い
副問合せと相関副問合せの二者について簡単に観てきたが、両者の違いとは何なのだろう?
副問合せの例では、社員が2名以上いる部署の社員氏名を抽出し、相関副問合せでは部署長である社員氏名を抽出している。
相関副問合せは、より小分けしたグループ内での比較に用いられるのである。
要するに表全体ではなく、表の一部に限定した比較を行いたいときに使用されるのだ。
まとめると、
列名 IN (副問合せ文):副問合せの結果と一致する列値が存在するかを調べる。
EXISTS (副問合せ文):副問合せ結果が1行でも存在するかを調べる。
なかなか分かりにくいので、これについては実際にトライしてみないといけないかなぁと思う。
・後記
副問合せと相関副問合せは、処理の過程がイメージできればよいのだが、その域に到達するためには相当訓練が必要になりそうだ。
パソコンをいじらなくても、ペンと紙で動きを記述するのもありかなと思う。