SQLの句(SQL clauses)
SELECT文を組み立てる部品。書く順番と、実際に処理される順番が違うため、WHEREとHAVINGの使い分けが問われる。
もう少し詳しい説明
SQLは関係データベースを操作する言語です。中心になるのが、データを取り出すSELECT文です。
SELECT文は、句と呼ばれる部品を決まった順に並べて作ります。
このページで使う表
句の説明では、何を書くと何が出てくるのかを毎回この表で見ていきます。店ごとの売上を1件ずつ記録した売上明細という表です。
| 店コード | 店名 | 都道府県 | 売上 |
|---|---|---|---|
| S01 | 新宿店 | 東京都 | 600000 |
| S01 | 新宿店 | 東京都 | 500000 |
| S02 | 渋谷店 | 東京都 | 400000 |
| S02 | 渋谷店 | 東京都 | 300000 |
| S03 | 横浜店 | 神奈川県 | 900000 |
| S03 | 横浜店 | 神奈川県 | 800000 |
1行が1件の売上です。同じ店が何度も出てきます。
書く順番
SELECT 列名
FROM 表名
WHERE 行の条件
GROUP BY まとめる基準の列
HAVING まとめたあとの条件
ORDER BY 並べ替えの基準
| 句 | 何をするか |
|---|---|
SELECT | どの列を出すか |
FROM | どの表から取るか |
WHERE | どの行を残すか |
GROUP BY | どの列が同じ行を1つにまとめるか |
HAVING | まとめたあとの条件 |
ORDER BY | 結果をどの順に並べるか |
この順番どおりに書かないと、文として成り立ちません。
1つずつ、何が出るのかを見る
SELECT と FROM だけなら、指定した列がそのまま全部出ます。
SELECT 店名, 売上
FROM 売上明細
| 店名 | 売上 |
|---|---|
| 新宿店 | 600000 |
| 新宿店 | 500000 |
| 渋谷店 | 400000 |
| 渋谷店 | 300000 |
| 横浜店 | 900000 |
| 横浜店 | 800000 |
6行のまま、列だけが2つに減りました。SELECT は列を選び、行は減らしません。
WHERE を足すと、行が減ります。
SELECT 店名, 売上
FROM 売上明細
WHERE 都道府県 = '東京都'
| 店名 | 売上 |
|---|---|
| 新宿店 | 600000 |
| 新宿店 | 500000 |
| 渋谷店 | 400000 |
| 渋谷店 | 300000 |
神奈川県の2行が消えました。 WHERE は、1行ずつ見て、条件に合わない行を落とします。
GROUP BY を足すと、行がまとまります。
SELECT 店コード, SUM(売上)
FROM 売上明細
GROUP BY 店コード
| 店コード | SUM(売上) |
|---|---|
| S01 | 1100000 |
| S02 | 700000 |
| S03 | 1700000 |
6行が3行になりました。 同じ店コードの行が1つにまとめられ、SUM(売上) がその店の合計になっています。まとめたあとは、1行が1つの店を表します。
ORDER BY を足すと、並び順が変わります。
SELECT 店コード, SUM(売上)
FROM 売上明細
GROUP BY 店コード
ORDER BY SUM(売上) DESC
| 店コード | SUM(売上) |
|---|---|
| S03 | 1700000 |
| S01 | 1100000 |
| S02 | 700000 |
行の数も中身も変わらず、並びだけが入れ替わりました。 DESC は大きいほうが先、という指定です。
書く順番と、処理される順番が違う
試験で問われるのは、ここです。
| 順番 | |
|---|---|
| 書く順番 | SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY |
| 処理される順番 | FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY |
SELECTは、いちばん先に書くのに、処理されるのはほぼ最後です。
この食い違いから、2つのことが決まります。
1. WHEREに集計関数を書けない。
WHERE が動くのは GROUP BY より前です。前の節で見たとおり、GROUP BY でまとめて初めて合計が出ます。WHERE の時点では、まだ1行ずつバラバラの状態で、合計という値がどこにも存在しません。
SELECT 店コード, SUM(売上)
FROM 売上明細
WHERE SUM(売上) > 1000000 ← これは書けない
GROUP BY 店コード
無いものと比べることはできないので、文として成り立ちません。
2. SELECTで付けた別名は、ORDER BYでは使えて、WHEREでは使えない。
AS を使うと、列に別の名前を付けられます。
SELECT 店コード, SUM(売上) AS 合計
FROM 売上明細
GROUP BY 店コード
ORDER BY 合計 DESC ← 使える
ORDER BY が動くのは SELECT のあとなので、そのときには「合計」という名前がもう付いています。
SELECT 店コード, SUM(売上) AS 合計
FROM 売上明細
WHERE 合計 > 1000000 ← 使えない
GROUP BY 店コード
WHERE が動くのは SELECT の前です。その時点では「合計」という名前はまだ付いていません。
どちらも、順番の1本から出てきます。 別々に覚えようとすると、どちらがどちらか毎回迷います。
WHEREとHAVINGの使い分け
| いつ効くか | 何に対する条件か | |
|---|---|---|
WHERE | まとめる前 | 1行ずつ |
HAVING | まとめたあと | グループごとの集計値 |
たとえば「東京都の店だけを対象に、売上合計が100万円を超える店を出す」なら、こうなります。
SELECT 店コード, SUM(売上) AS 合計
FROM 売上明細
WHERE 都道府県 = '東京都'
GROUP BY 店コード
HAVING SUM(売上) > 1000000
この文が、どう動くのかを順に追います。
① FROM … 売上明細の6行を取り出します。
| 店コード | 店名 | 都道府県 | 売上 |
|---|---|---|---|
| S01 | 新宿店 | 東京都 | 600000 |
| S01 | 新宿店 | 東京都 | 500000 |
| S02 | 渋谷店 | 東京都 | 400000 |
| S02 | 渋谷店 | 東京都 | 300000 |
| S03 | 横浜店 | 神奈川県 | 900000 |
| S03 | 横浜店 | 神奈川県 | 800000 |
② WHERE … 1行ずつ見て、都道府県が東京都でない行を落とします。
| 店コード | 店名 | 都道府県 | 売上 |
|---|---|---|---|
| S01 | 新宿店 | 東京都 | 600000 |
| S01 | 新宿店 | 東京都 | 500000 |
| S02 | 渋谷店 | 東京都 | 400000 |
| S02 | 渋谷店 | 東京都 | 300000 |
ここで横浜店が消えます。 合計すれば170万円で、いちばん大きい店です。それでも先に落ちているので、このあとの計算には出てきません。
③ GROUP BY … 店コードが同じ行を1つにまとめ、売上を合計します。
| 店コード | 合計 |
|---|---|
| S01 | 1100000 |
| S02 | 700000 |
④ HAVING … まとまった行を見て、合計が100万円を超えないものを落とします。
| 店コード | 合計 |
|---|---|
| S01 | 1100000 |
⑤ SELECT … 指定された列(店コードと合計)を出します。これが答えです。
| 店コード | 合計 |
|---|---|
| S01 | 1100000 |
都道府県の条件はWHERE(1行ずつで判断できる)、合計の条件はHAVING(まとめないと分からない)です。
この2つを入れ替えると、答えが変わります。 WHERE を外して HAVING だけにすると、横浜店が落ちないまま③へ進むので、S03(170万円)とS01(110万円)の2行が出ます。試験では、ここを入れ替えた選択肢が並びます。
集計関数
GROUP BYと組にして使います。
| 関数 | 何を出すか | NULLの扱い |
|---|---|---|
COUNT(*) | 行数 | NULLの行も数える |
COUNT(列名) | その列がNULLでない行数 | NULLは数えない |
SUM(列名) | 合計 | NULLは無視 |
AVG(列名) | 平均 | NULLは無視(分母にも入らない) |
MAX / MIN | 最大・最小 | NULLは無視 |
COUNT(*) と COUNT(列名) の違いは、そのまま出題されます。
AVGでも同じことが起きます。NULLの行は分母にも入りません。5行のうち2行がNULLなら、3で割った値が出ます。0として扱って5で割るわけではありません。
重複を消す
DISTINCT を付けると、同じ値が1つにまとめられます。
SELECT DISTINCT 店コード
FROM 売上明細
| 店コード |
|---|
| S01 |
| S02 |
| S03 |
DISTINCT を付けないと、売上明細の6行ぶんがそのまま出ます(S01が2行、S02が2行、S03が2行)。
SELECTは、何もしなければ重複を消しません。 消したいときだけ DISTINCT を付けます。これも取り違えやすいところです。
並べ替え
ORDER BY は、既定で昇順(小さいほうが先)です。
| 書き方 | 並び |
|---|---|
ORDER BY 売上 | 昇順(ASC を省いた形) |
ORDER BY 売上 DESC | 降順 |
ORDER BY 部署, 売上 DESC | 部署で昇順、同じ部署の中で売上の降順 |
列を2つ書いたときは、左が優先です。
表をつなぐ
複数の表から取り出すときは、つなぎ目の列を指定します。
SELECT 社員.氏名, 部署.部署名
FROM 社員 JOIN 部署 ON 社員.部署コード = 部署.部署コード
ON に書くのがつなぎ目、WHERE に書くのが絞り込みです。役割が違うので、分けて書きます。
この2つの表があるとします。
社員表
| 社員番号 | 氏名 | 部署コード |
|---|---|---|
| 1001 | 佐藤 | D01 |
| 1002 | 鈴木 | D02 |
| 1003 | 田中 | (空) |
部署表
| 部署コード | 部署名 |
|---|---|
| D01 | 営業部 |
| D02 | 開発部 |
田中には部署コードが入っていません。異動の途中など、つなぎ先がない行です。
つなぎ先がない行をどう扱うかで、結合の種類が分かれます。
| 書き方 | つなぎ先がない行 |
|---|---|
INNER JOIN(内部結合) | 消える |
LEFT OUTER JOIN(左外部結合) | 左の表の行は残り、右側がNULLになる |
INNER JOIN で結んだ結果です。
| 氏名 | 部署名 |
|---|---|
| 佐藤 | 営業部 |
| 鈴木 | 開発部 |
田中が消えました。 部署表につなぎ先が無いためです。
LEFT OUTER JOIN で結んだ結果です。
| 氏名 | 部署名 |
|---|---|
| 佐藤 | 営業部 |
| 鈴木 | 開発部 |
| 田中 | NULL |
田中が残り、部署名のところがNULL(値が入っていない状態)になります。 部署に所属していない社員も一覧に出したいなら、こちらを使います。内部結合では消えてしまいます。
試験ではこう出る
科目A(旧・午前)でいちばん多いのが、WHEREとHAVINGの使い分けです。「グループ化した結果に条件を付ける」と書いてあればHAVINGです。
次が、与えられたSELECT文の実行結果を答える形です。小さな表が示され、結果の行数や値を選びます。処理の順番(FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY)で追うと間違えません。
COUNT(*) と COUNT(列名) の差、NULLを含む列のAVGも繰り返し出ます。
応用情報では、結合を含む問合せの読み取りと、内部結合と外部結合で結果の行数が変わることが問われます。
関連する用語
- 関係データベース
- SQLはこれを操作する言語。表から表を作る
- 実表と導出表
- SELECT文に名前を付けたものがビュー
- 主キー
- 表を結合するとき、つなぎ目になる列
- インデックス
- WHEREで絞る列に付けると検索が速くなる
ミニクイズ
SQLで、グループごとに集計した結果に対して条件を付けたい。使う句として適切なものはどれか。
正解は 1番:HAVING句
集計したあとの結果に条件を付けるのはHAVING句です。WHERE句はグループにまとめる前の、1行ずつに対して条件を付けます。処理の順番がWHERE→GROUP BY→HAVINGなので、WHEREの時点ではまだ合計が出ていません。そのためWHEREにSUMやCOUNTを書くことはできません。GROUP BY句はまとめる基準になる列を指定する句、ORDER BY句は結果の並び順を決める句で、どちらも条件を付ける句ではありません。
この分野をまとめて解く → データベースのミニテスト(全35問)
最終更新:2026-10-20