| name | active | department_id |
|---|---|---|
| Alice | true | 10 |
| Bob | true | 10 |
| Carol | false | 20 |
| Dave | true | 20 |
| Eve | true | 30 |
Interactive
同じデータがどう変わるかを見る
「次へ」で順に進むか、対応する解説までスクロールしてください。
前の状態にもいつでも戻れます。
STEP 0
2つのテーブルから始める
データベースには、複数のテーブルがそれぞれ独立して存在しています。
| id | name |
|---|---|
| 10 | Sales |
| 20 | Dev |
| 30 | Support |
- 1同じdepartmentの行を囲う
- 2囲った行をグループの箱へ束ねる
| もともと users | もともと departments | |||
|---|---|---|---|---|
| user | active | usersdept_id | departmentsid | department JOINで追加 |
| Alice | true | 10 | 10 | Sales |
| Bob | true | 10 | 10 | Sales |
| Carol | false | 20 | 20 | Dev |
| Dave | true | 20 | 20 | Dev |
| Eve | true | 30 | 30 | Support |
1行を除外:Carol は active = false
2グループを除外:Dev・Support は COUNT(*) < 2
| dept_name | user_count |
|---|---|
| Sales | 2 |
必要な列だけを持つ、完成した結果です。
TABLES:まだ表どうしは接続されていません。
START
TABLES
処理の前には、users と departments が独立して存在しています。まずは、どの表からデータを取り出すかを FROM で決めます。
CONNECT
JOIN
department_id = id を手がかりに2つの表を結び、部署名の列を持ち込みます。JOIN後の行数は、結合条件とデータの関係によって増える・減る・同じのいずれもあり得ます。
FILTER ROWS
WHERE
active = true を1行ずつ判定し、条件に合わない Carol の行を除外します。WHEREが絞る対象は、グループではなく個々の行です。
MAKE GROUPS
GROUP BY
部署名が同じ行を Sales・Dev・Support の箱に束ねます。行を重複として削除する処理ではなく、COUNT・SUM・AVGなどを計算する単位を作る処理です。
GROUP BYの用語解説FILTER GROUPS
HAVING
COUNT(*) >= 2 を各グループに適用し、2人いる Sales だけを残します。HAVINGが絞る対象は、GROUP BY後のグループです。
SHAPE RESULT
SELECT
最後に、部署名と人数だけを取り出します。AS で結果列に読みやすい名前を付け、2列の完成した表へ整えます。
Mental Model
SQLは、表の形を段階的に変えていく
構文を個別に暗記する前に、「いま何を対象に、
表をどう変えているか」を意識してみましょう。
- STARTTABLES独立した表
- 01JOIN横に広がる
- 02WHERE行が減る
- 03GROUP BY束になる
- 04HAVING束が減る
- 05SELECT列が減る
Written order
SELECT → FROM → JOIN → WHERE → GROUP BY → HAVING
Logical order
FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT
この論理順序は学習用のモデルです。実際のDBMSは、同じ結果を効率よく返すために物理的な実行計画を組み替えることがあります。
JOIN Variations
JOINの違いは「どの行を残すか」で見る
円の重なりだけでなく、対応相手がいない行とNULLの位置を、実際の表で比べてみましょう。
| name | department_id |
|---|---|
| Alice | 10 |
| Bob | 10 |
| Frank | 99 |
| id | name |
|---|---|
| 10 | Sales |
| 40 | HR |
一致する行だけ
INNER JOIN
| user | department |
|---|---|
| Alice | Sales |
| Bob | Sales |
| Frank | — |
| — | HR |
左の表をすべて残す
LEFT OUTER JOIN
| user | department |
|---|---|
| Alice | Sales |
| Bob | Sales |
| Frank | NULL |
右の表をすべて残す
RIGHT OUTER JOIN
| user | department |
|---|---|
| Alice | Sales |
| Bob | Sales |
| NULL | HR |
WHERE vs HAVING
似ているけれど、絞る対象が違う
WHEREは「行」を絞る
Alice、Bob、Carol…という個々の行を条件判定します。集約前のデータ量を減らす役割です。
| user | department | active |
|---|---|---|
| Alice | Sales | true |
| Bob | Sales | true |
| Carol | Dev | false |
WHERE u.active = true
Carolの1行を除外
| user | department | active |
|---|---|---|
| Alice | Sales | true |
| Bob | Sales | true |
HAVINGは「束」を絞る
Sales、Dev、Supportというグループを、COUNTなどの集約結果を使って条件判定します。
| department | COUNT(*) |
|---|---|
| Sales | 2 |
| Dev | 1 |
| Support | 1 |
HAVING COUNT(*) >= 2
Dev・Supportの2グループを除外
| department | COUNT(*) |
|---|---|
| Sales | 2 |
Miria SQL Learning
流れが見えたら、
今度は自分で動かしてみよう。
インストール不要の学習環境で、SELECT文を実際に書いて確認できます。
ブラウザだけで実行できます