データベーススペシャリスト 2012年 午前2 問09
問題文
ある月の“月末商品在庫”表と“当月商品出荷実績”表を使って、ビュー“商品別出荷実績”を定義した。このビューにSQL文を実行した結果の値はどれか。

選択肢
ア:400(正解)
イ:500
ウ:600
エ:700
🔒 解説は解答すると表示されます
LEFT JOINのNULL扱い【午前2解説】
正解の理由
ビューの各行は「商品コードごとの出荷実績合計(SUM)」と月末在庫数を持ちます。各商品の出荷合計は次のとおりで、S002とS004は該当する出荷行がないため出荷実績数がNULLになります。
- S001: 50 + 100 = 150
- S002: NULL(出荷なし)
- S003: 150 + 150 = 300
- S004: NULL(出荷なし)
- S005: 100 + 250 = 350
WHERE句の条件「出荷実績数 <= 300」はNULLに対する比較ではUNKNOWN(偽扱い)になり、NULL行は除外されます。したがって条件を満たすのは出荷実績数が150のS001と300のS003だけで、月末在庫の合計は 100 + 300 = 400 となります。以上より選択肢アが正しいです。
解法ステップ
- ビュー定義のSELECT句で商品ごとにSUM(出荷数)を算出する。LEFT OUTER JOIN により、右側に該当行がなければ右側列はNULLとなる。
- 各商品について出荷実績数を計算する(上記の合計値を参照)。
- ビューに対する外側のSELECTでWHERE 出荷実績数 <= 300 を適用する。ここでNULL <= 300 は UNKNOWN となるため除外される。
- WHEREで残った行(S001, S003)の月末在庫数をSUMして答えを求める:100 + 300 = 400。
選択肢別の誤答解説
-
ア(400)
正しい理由は上記のとおり。S002/S004はNULLで除外、S001とS003のみを合算するため400になる。 -
イ(500)
500は「S003(300) + S005(200)」を合算した値です。これを選ぶ誤りは、S005の出荷合計(実際は350)を誤って0または未処理と見なして条件を通してしまったケースや、S001を誤って除外した計算ミスによるものです。実データではS005は350で条件を満たさないため誤りです。 -
ウ(600)
600は「S001(100) + S003(300) + S005(200)」の合算に相当します。これはS005の出荷合計を誤って250または0と見なしてしまう誤り(出荷数の合計ミス)で生じます。実際にはS005の出荷合計は350で条件を満たしません。 -
エ(700)
700は「S002(250) + S004(450)」を合算した値に相当します。これはSUMがNULLを0扱いして未出荷の商品を条件に通してしまった(NULL→0の誤認)場合に生じる典型的な誤りです。SQLの比較ではNULLは0とは扱われないため、この解釈は間違いです。
よくある誤解
-
SUMの結果が「0」になると誤解する
LEFT JOINで一致しない右側列があるとき、SUMは非NULL値がなければNULLを返します(0ではない)。NULLと数値の比較はUNKNOWNになり条件に合致しない点を取り違えやすいです。 -
WHEREとHAVINGの役割混同
集約後の条件はHAVINGで評価するのが原則と理解する人がいます。今回はビューに既に集約列があるため外側のWHEREでその列を比較できますが、集約結果に対するフィルタリングのタイミングとNULL扱いを混同すると誤答になります。 -
NULL比較の扱いを忘れる
「NULL <= 300 を偽とする」ことを忘れ、NULLを条件に合致すると誤認するミスが多いです。
補足コラム
該当ケースで「出荷実績が無ければ0扱いして条件に含めたい」場合は、ビューやクエリでNULLを0に変換すると意図どおりになります。例:
-- ビュー定義を変える例(NULLを0に置換)
CREATE VIEW 商品別出荷実績2 AS
SELECT
m.商品コード,
COALESCE(SUM(t.出荷数), 0) AS 出荷実績数,
m.在庫数
FROM 月末商品在庫 m
LEFT JOIN 当月商品出荷実績 t
ON m.商品コード = t.商品コード
GROUP BY m.商品コード, m.在庫数;
あるいは、ビューはそのままにして外側のクエリでCOALESCEを使う方法もあります。また、集約結果に対する条件を直接書く場合はHAVING句を用いるのが設計上明確です。
FAQ
Q: SUMがNULLを返すのはなぜですか?
A: グループ内に非NULLの値が1件もない場合、SUMはNULLになります(NULLは集計対象から除外されるため)。したがって「該当行なし=0」とは自動的に扱われません。
A: グループ内に非NULLの値が1件もない場合、SUMはNULLになります(NULLは集計対象から除外されるため)。したがって「該当行なし=0」とは自動的に扱われません。
Q: NULLを0扱いにしたいときはどうする?
A: COALESCE(SUM(...), 0) のようにNULLを明示的に0に変換してください。ビュー定義内でも外側のクエリでも適用可能です。
A: COALESCE(SUM(...), 0) のようにNULLを明示的に0に変換してください。ビュー定義内でも外側のクエリでも適用可能です。
Q: WHEREとHAVINGの違いは?
A: WHEREは行単位のフィルタ(グループ化の前)に使い、HAVINGはGROUP BYで作られたグループに対する条件(集約後)に使います。本問ではビューに集約列があるため外側のWHEREで参照していますが、集約直後に条件を付けたい場合はHAVINGが適切です。
A: WHEREは行単位のフィルタ(グループ化の前)に使い、HAVINGはGROUP BYで作られたグループに対する条件(集約後)に使います。本問ではビューに集約列があるため外側のWHEREで参照していますが、集約直後に条件を付けたい場合はHAVINGが適切です。
関連キーワード: LEFT OUTER JOIN、SUM、NULL扱い、COALESCE、HAVING、GROUP BY、集計結果のフィルタリング

\ せっかくなら /
データベーススペシャリストを
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

