データベーススペシャリスト 2013年 午前2 問05
問題文
社員表から、役割名がプログラマである社員が3人以上所属している部門の部門名を取得するSQL文はどれか。ここで、実線の下線は主キーを表す。
社員(社員番号、部門名、社員名、役割名)
選択肢
ア:
SELECT 部門名 FROM 社員
GROUP BY 部門名
HAVING COUNT(*) >= 3
WHERE 役割名='プログラマ'
イ:
SELECT 部門名 FROM 社員
WHERE COUNT(*) >= 3 AND 役割名='プログラマ'
GROUP BY 部門名
ウ:
SELECT 部門名 FROM 社員
WHERE COUNT(*) >= 3
GROUP BY 部門名
HAVING 役割名 = 'プログラマ'
エ:
SELECT 部門名 FROM 社員
WHERE 役割名='プログラマ'
GROUP BY 部門名
HAVING COUNT(*) >= 3
(正解)🔒 解説は解答すると表示されます
GROUP BYとHAVING【午前2解説】
正解の理由
部門ごとに「役割名がプログラマである社員」を絞り、その数が3以上である部門名を出すためには、まず行レベルで役割を限定(WHERE)し、その限定後の行を部門ごとに集約(GROUP BY)して、集約結果に対して件数条件を課す(HAVING)必要があります。選択肢エはこの手順どおりに記述されており、WHEREで役割名='プログラマ'を先に絞り、GROUP BY 部門名でグループ化した後、HAVING COUNT(*) >= 3で各グループの行数を評価しているため正解です。
(ポイント)
- WHEREは行単位の絞り込み、HAVINGはグループ単位の絞り込み
- 集約関数(COUNTなど)はWHEREでは使えないため、件数条件はHAVINGで評価する
解法ステップ
- 目的を明確にする:「部門ごとにプログラマの人数が3人以上」の部門名を取得する。
- プログラマである行だけを対象にする => WHERE 役割名 = 'プログラマ'
- 部門単位で集約する => GROUP BY 部門名
- 集約結果(各部門のプログラマ人数)に条件をつける => HAVING COUNT(*) >= 3
- SELECT で部門名を出力する
例(正しいSQLの一例):
SELECT 部門名
FROM 社員
WHERE 役割名 = 'プログラマ'
GROUP BY 部門名
HAVING COUNT(*) >= 3;
選択肢別の誤答解説
-
ア:
- HAVING は GROUP BY の後に位置する句で、文法順序が誤っています(HAVING が先、WHERE が後になっている)。さらに、WHERE句でグループ単位の条件を指定できない点が問題です。WHERE は行フィルタ、HAVING はグループフィルタであることを混同しています。
-
イ:
- WHERE句の中で COUNT(*) >= 3 のような集約関数を使っている点が誤りです。SQLでは集約関数による評価はグループ化後に行うため、集約条件は HAVING に書く必要があります。文の句順(WHERE の場所)は正しいものの、集約条件の書き場所が不適切です。
-
ウ:
- 二重の誤りがあります。
- WHERE COUNT(*) >= 3 としており、WHERE句で集約関数を使っている点が誤りです(集約は HAVING で行う)。
- HAVING 役割名 = 'プログラマ' としている点も誤りです。HAVING で非集約列(役割名)を単独で条件にするには、その列が GROUP BY に含まれている必要があります。ここでは GROUP BY は部門名のみであり、役割名はグループ化列に含まれていないため、HAVING で役割名を直接比較するのは正しくありません(HAVING は原則として集約関数か、GROUP BY に含まれる列を条件にするため)。なお、HAVING を使う際に非集約列を参照できるかはDBMSによる差異もありますが、一般的な正しい書き方は「先にWHEREで役割名を絞る」ことです。
- 二重の誤りがあります。
-
エ:
- WHERE で役割名を先に限定し、GROUP BY 部門名 で部門ごとに集約し、HAVING で COUNT() >= 3 を判定しているため要件どおりです。COUNT() は行数を数えるので、社員番号が主キーであることから重複やNULLの影響を受けず期待どおりに動作します。
よくある誤解
- HAVINGは必ずGROUP BYが必要である:
- 一般的な使い方はGROUP BYと併用してグループごとの条件を指定することですが、標準SQLでは GROUP BY を省略した場合に全行を1つのグループとして扱い HAVING を使えるケースがあります(DBMSによって挙動の差があります)。ただし、本問のように「部門ごとに判定する」目的では GROUP BY が必須です。
- WHEREで集約関数を使える:
- WHEREは集約前の行フィルタなので、COUNT(*) のような集約関数は使えません。集約に基づく条件はHAVINGに書く必要があります。
- HAVINGで非集約列を自由に参照できる:
- HAVINGで非集約列を条件にするには、その列がGROUP BYに含まれているか、DBMSが拡張を許す場合のみです。標準的には、グループ化されていない列をHAVINGで単独参照するのは誤りです。
補足コラム
- COUNT(*) と COUNT(列) の違い:
- COUNT() は行数を数え、NULLも含めて行をカウントします(列にNULLがあっても行はカウントされる)。COUNT(役割名) は役割名がNULLでない行だけを数えます。本問では役割名で絞ってから集約しているため、COUNT() がシンプルで確実です。
- パフォーマンス観点:
- 可能ならWHEREで早めに行数を減らす(ここでは役割名で絞る)ことで、GROUP BY の負荷を下げられます。大規模データではインデックスの有無やDBMSの実行計画を確認するとよいです。
FAQ
Q1: HAVING を使うときに必ず GROUP BY が必要ですか?
A1: 通常はGROUP BYと併用してグループごとの条件を指定しますが、SQLではGROUP BYを省略すると全行を単一グループとして扱い HAVING を使える場合があります。ただしDBMSによる挙動差があるため、目的がグループ毎の判定なら明示的に GROUP BY を書くのが安全です。
A1: 通常はGROUP BYと併用してグループごとの条件を指定しますが、SQLではGROUP BYを省略すると全行を単一グループとして扱い HAVING を使える場合があります。ただしDBMSによる挙動差があるため、目的がグループ毎の判定なら明示的に GROUP BY を書くのが安全です。
Q2: COUNT() と COUNT(1) はどちらが速いですか?
A2: 多くのDBMSではほぼ同等で、最適化により同じ実行計画になります。可読性の観点で COUNT() を使うことが一般的です。
A2: 多くのDBMSではほぼ同等で、最適化により同じ実行計画になります。可読性の観点で COUNT() を使うことが一般的です。
Q3: 非集約列を HAVING で条件にしてもよいのですか?
A3: 標準的には、HAVING 条件内で非集約列を参照する場合、その列は GROUP BY に含める必要があります。データベースによっては拡張を許して暗黙の動作をするものもありますが、移植性の観点から避けるべきです。
A3: 標準的には、HAVING 条件内で非集約列を参照する場合、その列は GROUP BY に含める必要があります。データベースによっては拡張を許して暗黙の動作をするものもありますが、移植性の観点から避けるべきです。
関連キーワード: SQL、GROUP BY、HAVING、WHERE、COUNT(*)、集約関数、句の順序、集計フィルタリング

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

