基本情報技術者 2014年 春期 午前(科目A) 問28
問題文
“商品“表、“在庫“表に対する次のSQL文の結果と同じ結果が得られるSQL文はどれか。ここで、下線部は主キーを表す。
SELECT 商品番号 FROM 商品
WHERE 商品番号 NOT IN (SELECT 商品番号 FROM 在庫)

選択肢
ア:SELECT 商品番号 FROM 在庫
WHERE EXISTS (SELECT 商品番号 FROM 商品)
イ:SELECT 商品番号 FROM 在庫
WHERE NOT EXISTS (SELECT 商品番号 FROM 商品)
ウ:SELECT 商品番号 FROM 商品
WHERE EXISTS (SELECT 商品番号 FROM 在庫
WHERE 商品.商品番号 = 在庫.商品番号)
エ:SELECT 商品番号 FROM 商品
WHERE NOT EXISTS (SELECT 商品番号 FROM 在庫
WHERE 商品.商品番号 = 在庫.商品番号)(正解)
🔒 解説は解答すると表示されます
NOT IN と NOT EXISTS の等価性【午前解説】
正解の理由
正解は エ です。元のSQL
SELECT 商品番号 FROM 商品 WHERE 商品番号 NOT IN (SELECT 商品番号 FROM 在庫)
は「商品表の商品番号が在庫表のいずれの行の[商品番号]とも一致しない」行を選びます。これを相関サブクエリとNOT EXISTSで表すと、
SELECT 商品番号 FROM 商品 WHERE NOT EXISTS (SELECT 商品番号 FROM 在庫 WHERE 商品.商品番号 = 在庫.商品番号)
となり、選択肢エと同一の意味になります。相関条件があるため各商品行ごとに在庫表を検索し、該当する在庫行が存在しない場合にその商品番号を返します。
解法ステップ
- 元のSQLの意味を日本語で言い換える:「商品表のうち、在庫表にその商品番号が存在しない商品番号を取得」
- NOT IN を NOT EXISTS に置き換えるには相関サブクエリが必要で、外側の行を参照する条件(商品.商品番号 = 在庫.商品番号)を入れる。
- NULLの影響を確認する。もし在庫.商品番号がNULLを取り得る場合、NOT INは期待通りに動かない可能性があるためNOT EXISTSの使用が安全。
- 選択肢と照合して、相関条件を含むNOT EXISTSを選ぶ(エ)。
選択肢別の誤答解説
- ア: SELECT 商品番号 FROM 在庫 WHERE EXISTS (SELECT 商品番号 FROM 商品)
- 誤り。外側が在庫表になっており、条件は「商品表に何か行があれば在庫のすべての行を返す」になってしまい意味が逆です。
- イ: SELECT 商品番号 FROM 在庫 WHERE NOT EXISTS (SELECT 商品番号 FROM 商品)
- 誤り。これも在庫表を主にしており、且つ商品表に行が無ければ在庫の全行を返す、元の目的と全く異なります。
- ウ: SELECT 商品番号 FROM 商品 WHERE EXISTS (SELECT 商品番号 FROM 在庫 WHERE 商品.商品番号 = 在庫.商品番号)
- 誤り。これは在庫に存在する商品だけを返す(IN の肯定版)ので、元のクエリの否定(在庫に存在しない商品)とは逆の集合になります。
- エ: SELECT 商品番号 FROM 商品 WHERE NOT EXISTS (SELECT 商品番号 FROM 在庫 WHERE 商品.商品番号 = 在庫.商品番号)
- 正解。商品表を主にし、相関付きNOT EXISTSで在庫に存在しない商品番号を返すため元のSQLと同等の結果になります。
よくある誤解
- 誤解1:NOT IN と NOT EXISTS は常に等価だと思い込む。実際はサブクエリがNULLを含むとNOT INは期待通りの結果を返さなくなります。
- 誤解2:EXISTS / NOT EXISTS のサブクエリに相関条件を書かずに使えば同じ結果になると考える。相関条件がなければ存在チェックの対象が変わり誤った結果になります。
- 誤解3:対象テーブルを間違えて在庫表から商品を選ぶようなクエリ(在庫表を主にしている)を等価と思うケース。元の問は商品表を主にしています。
補足コラム
- NULLの扱い
- NOT IN サブクエリがNULLを含むと、比較は未知(UNKNOWN)となり外側の行がフィルタされてしまうことがあります(結果が空になる場合も)。一方 NOT EXISTS は行の存在そのものを評価するためNULLの影響を受けにくく、安全な書き方です。
- LEFT JOIN を使う代替
- 同じ結果は LEFT JOIN と IS NULL でも得られます。例:
SELECT P.商品番号
FROM 商品 P
LEFT JOIN 在庫 S ON P.商品番号 = S.商品番号
WHERE S.商品番号 IS NULL;
- 実行計画やパフォーマンスはRDBMSやインデックス状況に依存します。
FAQ
Q1. NOT IN と NOT EXISTS はどちらを使うべきですか?
A1. サブクエリの列がNULLを取り得る可能性があるならNOT EXISTS(相関サブクエリ)を推奨します。NULLが絶対にありえない・制約で保証されているならどちらでも論理的に等価です。
A1. サブクエリの列がNULLを取り得る可能性があるならNOT EXISTS(相関サブクエリ)を推奨します。NULLが絶対にありえない・制約で保証されているならどちらでも論理的に等価です。
Q2. 相関条件を省略するとどうなる?
A2. 相関条件を省略すると外側の行(商品)ごとの存在チェックにならず、常に同じ真偽値を返すか意図しない集合が返るため誤りです。
A2. 相関条件を省略すると外側の行(商品)ごとの存在チェックにならず、常に同じ真偽値を返すか意図しない集合が返るため誤りです。
Q3. LEFT JOIN の方が速い場合はありますか?
A3. 場合によります。データ量やインデックス、RDBMSの最適化によってはLEFT JOIN + IS NULLの方が高速なこともあります。実行計画を確認してください。
A3. 場合によります。データ量やインデックス、RDBMSの最適化によってはLEFT JOIN + IS NULLの方が高速なこともあります。実行計画を確認してください。
関連キーワード: SQL、NOT IN、NOT EXISTS、EXISTS、サブクエリ、NULL、外部結合、相関サブクエリ、パフォーマンス

\ せっかくなら /
基本情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

