データベースの基礎
顧客表(顧客ID, 氏名)と注文表(注文ID, 顧客ID, 金額)から、一度も注文していない顧客の氏名を求めたい。正しいSQL文はどれか。
- ASELECT 氏名 FROM 顧客 WHERE EXISTS (SELECT * FROM 注文 WHERE 注文.顧客ID = 顧客.顧客ID)
- BSELECT 氏名 FROM 顧客 WHERE NOT EXISTS (SELECT * FROM 注文)
- CSELECT 氏名 FROM 顧客 WHERE NOT EXISTS (SELECT * FROM 注文 WHERE 注文.顧客ID = 顧客.顧客ID)
答えと解説を見る
正解:C. SELECT 氏名 FROM 顧客 WHERE NOT EXISTS (SELECT * FROM 注文 WHERE 注文.顧客ID = 顧客.顧客ID)
EXISTSは、括弧の中の副問い合わせが1行でも結果を返せば真、1行も返さなければ偽になる述語で、NOT EXISTSはその逆です。副問い合わせの中で 注文.顧客ID = 顧客.顧客ID のように外側の表の列を使うと、外側の顧客表の1行ごとに、その顧客の注文があるかどうかを調べる相関副問い合わせになります。これをNOT EXISTSと組み合わせると、注文が1件もない顧客だけが残ります。EXISTSにすると、逆に注文したことがある顧客が求まります。副問い合わせに顧客と対応させる条件がないと、注文表に1行でもあれば副問い合わせは常に行を返すので、NOT EXISTSは常に偽になり、結果は0行になります。同じ結果は、LEFT OUTER JOIN で結合して、注文側の列がNULLになる行を選ぶ方法でも得られます。
- A. EXISTSなので、注文したことがある顧客が求まります。
- B. 副問い合わせが顧客ごとの条件になっていないので、注文表に1行でもあれば結果は0行になります。
- C. 正しい。顧客ごとに注文の有無を調べ、注文が1件もない顧客だけを残します。