データベーススペシャリスト 2014年 午前2 問10
問題文
“社員”表から、男女それぞれの最年長社員を除く全ての社員を取り出すSQL文とするために、(a)に入る問合せはどれか。ここで、"社員”表の構造は次のとおりであり、下線は主キーを表す。
社員(社員番号, 社員名, 性別, 生年月日)
SELECT 社員番号, 社員名 FROM 社員 AS S1
WHERE 生年月日 > (a)
選択肢
ア:
SELECT MIN(生年月日) FROM 社員 AS S2
GROUP BY S2.性別
イ:
SELECT MIN(生年月日) FROM 社員 AS S2
WHERE S1.生年月日 > S2.生年月日
OR S1.性別=S2.性別
ウ:
SELECT MIN(生年月日)
FROM 社員 AS S2 WHERE S1.性別=S2.性別
(正解) エ:
SELECT MIN(生年月日) FROM 社員
GROUP BY S2.性別
🔒 解説は解答すると表示されます
性別ごとの最年長抽出【午前2解説】
正解の理由
外側の WHERE で「生年月日 > (a)」となっているため、サブクエリ (a) は各行に対して同一性別の最小(最も古い)生年月日を返す必要があります。選択肢 ウ の
SELECT MIN(生年月日)
FROM 社員 AS S2 WHERE S1.性別=S2.性別
は外側の行の性別を参照する相関サブクエリになっており、外側の社員(S1)と同じ性別に絞った集合の最小生年月日を 1 値で返します。外側条件「生年月日 > (その性別の最小生年月日)」は、最年長(最小生年月日)と等しい行を除外し、それ以外の同性別社員を残すため目的に合致します。
ポイント:
- 「最年長」は生年日がもっとも古い=数値的に最小(最も小さい日付)であること。
- 相関サブクエリ内の集約関数 MIN を使い、外側行の性別で絞ればスカラー(単一値)になるため比較可能。
解法ステップ
- 問題の意味を整理する:男女それぞれの最年長社員を除く全員を取り出したい。つまり各性別で最小の生年月日と等しい行だけを除外する。
- 外側クエリは WHERE 生年月日 > (a) であり、(a) は「その社員と同じ性別の最小生年月日」を返すことが必要。
- 外側の行の属性を使ってサブクエリを絞るには相関サブクエリ(S1 を参照する WHERE)が有効。相関サブクエリ内で MIN を使えば、その性別に対する最小値を 1 値で返す。
- 以上により、選択肢 ウ が要件を満たす。
選択肢別の誤答解説
- ア:
SELECT MIN(生年月日) FROM 社員 AS S2 GROUP BY S2.性別- 問題となる点は「GROUP BY によって性別ごとの最小生年月日が複数行で返る」ため、外側の WHERE に置いた場合はスカラ(1 値)を期待する文脈で多値サブクエリとなり不適です(多値サブクエリは等号や単一値比較ではエラー)。エイリアスの「S2」がサブクエリ内で使える点自体は問題ではありませんが、用途に適した単一値を返していないのが誤りの本質です。
- イ:
SELECT MIN(生年月日) FROM 社員 AS S2 WHERE S1.生年月日 > S2.生年月日 OR S1.性別=S2.性別- この条件は「同一性別を含め、さらに外側より生年月日が古い他性別の行も含める」ことになり得るため、MIN の結果がその性別の最小値とは限らなくなります。すなわち、他性別でさらに古い生年月日があればそれが選ばれ、意図した「その性別の最小生年月日」を返さないため誤りです。
- ウ:
SELECT MIN(生年月日) FROM 社員 AS S2 WHERE S1.性別=S2.性別- 相関条件で同じ性別に絞り、その集合の MIN を返すため、外側の WHERE 比較に使える単一値となり要件を満たします(正答の理由は上記参照)。
- エ:
SELECT MIN(生年月日) FROM 社員 GROUP BY S2.性別- 文法的にまず問題があります。GROUP BY 句で参照している
S2.性別のエイリアスS2は定義されていません(FROM 句に AS S2 がない)。また、仮にGROUP BY 性別と直してもアと同様に複数行が返るため単一値比較に使えず不適です。
- 文法的にまず問題があります。GROUP BY 句で参照している
よくある誤解
- 「GROUP BY を使えば性別ごとの最小値が得られるから正解」という誤解:確かに GROUP BY で性別ごとの最小値は得られますが、サブクエリを単一値(スカラー値)として使う文脈では複数行を返してはいけません。多値を返すケースは IN や EXISTS など別の文脈で扱います。
- 「相関サブクエリは必ず GROUP BY が必要」という誤解:相関サブクエリ内で外側の列で絞り込めば、集約関数(MIN や MAX)だけで目的の単一値を得られることが多く、GROUP BY は不要です。
- 「最年長=生年月日が大きい/新しい」との混同:日付の大小に関する直感ミス。古い生年月日は日付値として小さい(例:1980-01-01 < 1990-01-01)ため「最年長=MIN」を忘れないこと。
補足コラム
サブクエリ以外の書き方(代替手段)を示します。ウィンドウ関数を使うと直感的に書けます(SQL Server / PostgreSQL 等):
-- ウィンドウ関数で各性別の最年長にフラグを付け、それを除外する例
SELECT 社員番号, 社員名, 性別, 生年月日
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY 性別 ORDER BY 生年月日 ASC) AS rn
FROM 社員
) t
WHERE rn > 1;
または JOIN を使う方法(サブクエリで性別ごとの最小値を得て結合):
-- 性別ごとの最小生年月日を求めてから結合し、最年長を除外
SELECT s.社員番号, s.社員名
FROM 社員 s
JOIN (
SELECT 性別, MIN(生年月日) AS min_bd
FROM 社員
GROUP BY 性別
) m ON s.性別 = m.性別
WHERE s.生年月日 > m.min_bd;
ウィンドウ関数は可読性・柔軟性が高く、特に「トップ N」を性別ごとに選ぶなどの要件で便利です。
FAQ
Q. なぜサブクエリに GROUP BY を書いてはいけないのですか?
A. 書ける場合もありますが、外側の WHERE が単一値を期待しているなら GROUP BY による複数行の戻り値は不適です。複数行を返すサブクエリを単一値比較に使うとエラーになります(あるいは意図しない動作)。目的に応じて相関サブクエリ(外側の行で絞る+集約)か、JOIN/ウィンドウ関数を使って正しく処理してください。
A. 書ける場合もありますが、外側の WHERE が単一値を期待しているなら GROUP BY による複数行の戻り値は不適です。複数行を返すサブクエリを単一値比較に使うとエラーになります(あるいは意図しない動作)。目的に応じて相関サブクエリ(外側の行で絞る+集約)か、JOIN/ウィンドウ関数を使って正しく処理してください。
Q. 相関サブクエリはパフォーマンスが悪いのでは?
A. 相関サブクエリは実装やデータ量によっては非効率になることがあります。大規模データではウィンドウ関数や事前に集約した結果との JOIN の方が高速なことが多いです。実行計画を確認して選択してください。
A. 相関サブクエリは実装やデータ量によっては非効率になることがあります。大規模データではウィンドウ関数や事前に集約した結果との JOIN の方が高速なことが多いです。実行計画を確認して選択してください。
関連キーワード: SQL、相関サブクエリ、GROUP BY、集約関数、ウィンドウ関数、JOIN、スカラサブクエリ、最年長抽出

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

