🔀 Step 11: 様々な結合方法
LEFT JOINで全データを取得しよう!
- INNER JOINの課題(表示されないデータがある)
- LEFT JOIN(左外部結合)の使い方
- INNER JOINとLEFT JOINの違い
- NULLを使った「まだ〇〇していない」データの抽出
- COALESCE関数でNULLを別の値に変換
- 複数テーブルのLEFT JOIN
- 実務でよく使う結合パターン
🎯 1. INNER JOINの課題
1-1. INNER JOINの復習
前のStep 10で学んだINNER JOINは、両方のテーブルに存在するデータだけを取得します。
これは便利ですが、問題もあります。
1-2. 練習用テーブルの準備
今回は、Step 10で作った3つのテーブルをそのまま使います。まだ作っていない場合は、以下のSQLを実行してください。
ステップ1:顧客テーブルを作成(5人)
※横にスクロールできます
ステップ2:商品テーブルを作成(5件)
※横にスクロールできます
ステップ3:注文テーブルを作成(6件)
※横にスクロールできます
1-3. テーブルの内容を確認
| 顧客ID | 顧客名 | 都道府県 |
|---|---|---|
| 1 | 田中太郎 | 東京都 |
| 2 | 佐藤花子 | 大阪府 |
| 3 | 鈴木次郎 | 神奈川県 |
| 4 | 高橋美咲 | 福岡県 |
| 5 | 山田三郎 | 北海道 |
注意:顧客ID 4(高橋美咲)と5(山田三郎)は注文していません。
| 注文ID | 顧客ID | 商品ID | 数量 | 注文日 |
|---|---|---|---|---|
| 1 | 1 | 101 | 3 | 2024-11-01 |
| 2 | 1 | 102 | 5 | 2024-11-03 |
| 3 | 2 | 101 | 2 | 2024-11-05 |
| 4 | 2 | 104 | 4 | 2024-11-08 |
| 5 | 3 | 103 | 6 | 2024-11-10 |
| 6 | 1 | 105 | 2 | 2024-11-12 |
注意:顧客ID 1(田中太郎)は3回、顧客ID 2(佐藤花子)は2回、顧客ID 3(鈴木次郎)は1回注文しています。顧客ID 4と5の注文はありません。
1-4. INNER JOINで結合してみる
※横にスクロールできます
| 顧客ID | 顧客名 | 注文ID | 数量 |
|---|---|---|---|
| 1 | 田中太郎 | 1 | 3 |
| 1 | 田中太郎 | 2 | 5 |
| 1 | 田中太郎 | 6 | 2 |
| 2 | 佐藤花子 | 3 | 2 |
| 2 | 佐藤花子 | 4 | 4 |
| 3 | 鈴木次郎 | 5 | 6 |
結果を見てください。高橋美咲さんと山田三郎さんがいません!
INNER JOINは「両方のテーブルに存在するデータだけ」を取得するので、注文していない顧客は表示されないのです。
- 「全顧客のリストを見たい」のに、注文した顧客しか見えない
- 「まだ注文していない顧客」を見つけたい
- 「全商品のリストを見たい」のに、注文された商品しか見えない
そこで登場するのがLEFT JOINです!
⬅️ 2. LEFT JOIN(左外部結合)
2-1. LEFT JOINとは?
LEFT JOIN(レフト ジョイン)は、左側(FROM句)のテーブルの全ての行を表示します。
右側のテーブルにマッチするデータがなくても、左側は必ず表示されます。
学校のクラス名簿を思い浮かべてください。
- INNER JOIN:「テストを受けた生徒」だけのリスト(欠席者は載らない)
- LEFT JOIN:「全生徒」のリスト(欠席者は点数欄が空白)
2-2. LEFT JOINの基本構文
SELECT 列名 FROM テーブル1(左側・全て表示) LEFT JOIN テーブル2(右側・一致するもの) ON テーブル1.共通列 = テーブル2.共通列;
| 部分 | 意味 |
|---|---|
FROM テーブル1 |
左側のテーブル → 全行が表示される |
LEFT JOIN テーブル2 |
右側のテーブル → 一致するものだけ表示 |
ON 条件 |
どの列で繋ぐかを指定 |
2-3. LEFT JOINを使ってみよう
先ほどと同じクエリを、INNER JOINからLEFT JOINに変えてみましょう。
※横にスクロールできます
| 部分 | 意味 |
|---|---|
FROM 顧客 AS c |
顧客テーブルを左側(全て表示)に配置 |
LEFT JOIN 注文 AS o |
注文テーブルを右側に配置 |
ON c.顧客ID = o.顧客ID |
顧客IDが一致するデータを繋げる |
| 顧客ID | 顧客名 | 注文ID | 数量 |
|---|---|---|---|
| 1 | 田中太郎 | 1 | 3 |
| 1 | 田中太郎 | 2 | 5 |
| 1 | 田中太郎 | 6 | 2 |
| 2 | 佐藤花子 | 3 | 2 |
| 2 | 佐藤花子 | 4 | 4 |
| 3 | 鈴木次郎 | 5 | 6 |
| 4 | 高橋美咲 | NULL | NULL |
| 5 | 山田三郎 | NULL | NULL |
黄色の行に注目!高橋美咲さんと山田三郎さんも表示されました。注文がないので、注文IDと数量はNULLになっています。
- 左側(FROM)のテーブルは全行が表示される
- 右側にマッチがない場合、右側の列はNULLになる
- 「全件表示 + 追加情報」というイメージ
🔄 3. INNER JOINとLEFT JOINの比較
3-1. 図で理解する
| 結合方法 | 表示されるデータ | イメージ |
|---|---|---|
| INNER JOIN | 両方にあるデータだけ | 共通部分だけ(AND) |
| LEFT JOIN | 左側は全て、右側は一致するもの | 左側全部 + 一致する右側 |
3-2. 具体的な件数で比較
| 項目 | INNER JOIN | LEFT JOIN |
|---|---|---|
| 全顧客数 | 5人 | 5人 |
| 結果の行数 | 6行(注文がある顧客だけ) | 8行(全顧客を含む) |
| 表示される顧客 | 3人(田中、佐藤、鈴木) | 5人(全員) |
| 高橋美咲さん | 表示されない | 表示される(注文はNULL) |
3-3. どちらを使えばいい?
| 目的 | 使う結合 | 例 |
|---|---|---|
| 関連があるものだけ見たい | INNER JOIN | 注文がある顧客だけ |
| 全件を見たい(関連の有無に関わらず) | LEFT JOIN | 全顧客(注文の有無に関わらず) |
| 「まだ〇〇していない」を見つけたい | LEFT JOIN + IS NULL | まだ注文していない顧客 |
実務ではLEFT JOINの方がよく使います!
3-4. GROUP BYと組み合わせて比較
INNER JOINの場合:
※横にスクロールできます
| 顧客名 | 注文件数 |
|---|---|
| 田中太郎 | 3 |
| 佐藤花子 | 2 |
| 鈴木次郎 | 1 |
高橋美咲さんと山田三郎さんは表示されません。
LEFT JOINの場合:
※横にスクロールできます
| 顧客名 | 注文件数 |
|---|---|
| 田中太郎 | 3 |
| 佐藤花子 | 2 |
| 鈴木次郎 | 1 |
| 高橋美咲 | 0 |
| 山田三郎 | 0 |
注文0件の顧客も表示されます!COUNT(o.注文ID)はNULLを数えないので、自動的に0になります。
🔍 4. NULLを使った絞り込み
4-1. 「まだ〇〇していない」データを見つける
LEFT JOINで生まれたNULLを使うと、「まだ〇〇していない」データを見つけられます。
これは実務で非常によく使うテクニックです。
4-2. まだ注文していない顧客を探す
※横にスクロールできます
| 部分 | 意味 | なぜ必要? |
|---|---|---|
FROM 顧客 AS c |
顧客テーブルを全て表示 | 全顧客を対象にするため |
LEFT JOIN 注文 AS o |
注文テーブルと結合 | 注文の有無を調べるため |
ON c.顧客ID = o.顧客ID |
顧客IDで結合 | 顧客と注文を紐づけるため |
WHERE o.注文ID IS NULL |
注文IDがNULLの行だけ | 注文がない顧客を抽出するため |
| 顧客ID | 顧客名 | 都道府県 |
|---|---|---|
| 4 | 高橋美咲 | 福岡県 |
| 5 | 山田三郎 | 北海道 |
まだ一度も注文していない顧客が見つかりました!
- ✅ 正しい:
WHERE o.注文ID IS NULL - ❌ 間違い:
WHERE o.注文ID = NULL
NULLは「値がない」という特別な状態なので、等号(=)では比較できません。必ずIS NULLまたはIS NOT NULLを使います。
4-3. まだ注文されていない商品を探す
※横にスクロールできます
| 商品ID | 商品名 | 価格 |
|---|---|---|
| (該当なし – 全商品が1回以上注文されています) | ||
今回のデータでは、全ての商品が少なくとも1回は注文されているため、結果は0件です。
✨ 5. COALESCE関数 – NULLを別の値に変換
5-1. COALESCEとは?
COALESCE(コアレス)は、NULLを別の値に置き換える関数です。
LEFT JOINでNULLが発生したとき、0や「未購入」などの分かりやすい値に変換できます。
COALESCE(値, NULLの場合の代替値)
意味:値がNULLでなければその値を、NULLなら代替値を返す
5-2. 合計購入数量をNULLから0に変換
COALESCEなしの場合:
※横にスクロールできます
| 顧客名 | 購入数量合計 |
|---|---|
| 田中太郎 | 10 |
| 佐藤花子 | 6 |
| 鈴木次郎 | 6 |
| 高橋美咲 | NULL |
| 山田三郎 | NULL |
NULLは「値がない」という意味ですが、表示上は分かりにくいですね。
COALESCEありの場合:
※横にスクロールできます
| 顧客名 | 購入数量合計 |
|---|---|
| 田中太郎 | 10 |
| 佐藤花子 | 6 |
| 鈴木次郎 | 6 |
| 高橋美咲 | 0 |
| 山田三郎 | 0 |
NULLが0に変換され、分かりやすくなりました!
5-3. 文字列に変換する例
※横にスクロールできます
| 顧客名 | 注文件数 | 最終購入日 |
|---|---|---|
| 田中太郎 | 3 | 2024-11-12 |
| 佐藤花子 | 2 | 2024-11-08 |
| 鈴木次郎 | 1 | 2024-11-10 |
| 高橋美咲 | 0 | 未購入 |
| 山田三郎 | 0 | 未購入 |
| 用途 | 書き方 |
|---|---|
| NULLを0に変換 | COALESCE(SUM(列名), 0) |
| NULLを文字列に変換 | COALESCE(列名, '未登録') |
| 複数の候補から最初の非NULLを返す | COALESCE(列1, 列2, 列3, 'デフォルト') |
🔗 6. 複数テーブルのLEFT JOIN
6-1. 3つのテーブルをLEFT JOINで繋ぐ
LEFT JOINも複数回使えます。全顧客に、注文情報と商品情報を追加してみましょう。
※横にスクロールできます
- FROM 顧客 AS c:顧客テーブルを起点にする(全5人)
- LEFT JOIN 注文 AS o:注文テーブルと結合(注文がない顧客もNULLで残る)
- LEFT JOIN 商品 AS p:さらに商品テーブルと結合
| 顧客名 | 注文ID | 商品名 | 数量 |
|---|---|---|---|
| 田中太郎 | 1 | りんご | 3 |
| 田中太郎 | 2 | みかん | 5 |
| 田中太郎 | 6 | お茶 | 2 |
| 佐藤花子 | 3 | りんご | 2 |
| 佐藤花子 | 4 | オレンジジュース | 4 |
| 鈴木次郎 | 5 | バナナ | 6 |
| 高橋美咲 | NULL | NULL | NULL |
| 山田三郎 | NULL | NULL | NULL |
注文のない顧客も表示されています!
6-2. 全顧客の購入金額を計算
※横にスクロールできます
| 顧客名 | 注文件数 | 購入数量 | 購入金額 |
|---|---|---|---|
| 田中太郎 | 3 | 10 | 1190 |
| 佐藤花子 | 2 | 6 | 940 |
| 鈴木次郎 | 1 | 6 | 720 |
| 高橋美咲 | 0 | 0 | 0 |
| 山田三郎 | 0 | 0 | 0 |
全顧客の購入状況が一覧できます!
💼 7. 実務でよく使うパターン
7-1. 顧客のランク分け(ABC分析)
購入金額に応じて顧客をランク分けする、マーケティングでよく使う分析です。
※横にスクロールできます
| 顧客名 | 購入金額 | ランク |
|---|---|---|
| 田中太郎 | 1190 | A(優良) |
| 佐藤花子 | 940 | B(一般) |
| 鈴木次郎 | 720 | B(一般) |
| 高橋美咲 | 0 | D(未購入) |
| 山田三郎 | 0 | D(未購入) |
7-2. 商品の売れ行き分析
全商品の販売状況を一覧表示します。売れていない商品も含めて確認できます。
※横にスクロールできます
| 商品名 | カテゴリ | 価格 | 注文件数 | 販売数量 | 売上金額 |
|---|---|---|---|---|---|
| りんご | 果物 | 150 | 2 | 5 | 750 |
| バナナ | 果物 | 120 | 1 | 6 | 720 |
| オレンジジュース | 飲料 | 160 | 1 | 4 | 640 |
| みかん | 果物 | 100 | 1 | 5 | 500 |
| お茶 | 飲料 | 120 | 1 | 2 | 240 |
🎯 8. その他の結合方法
8-1. RIGHT JOIN(右外部結合)
RIGHT JOINは、LEFT JOINの逆で、右側のテーブルを全て表示します。
ただし、実務ではほとんど使いません。LEFT JOINでテーブルの順番を入れ替えれば同じことができるからです。
- LEFT JOINの方が読みやすい(左から右に読む習慣)
- テーブルの順番を変えればLEFT JOINで同じ結果が得られる
- チームで統一した方がいい(混在すると混乱する)
結論:LEFT JOINだけ覚えればOK!
8-2. FULL OUTER JOIN(完全外部結合)
両方のテーブルの全ての行を表示します。ただし、SQLiteはサポートしていません。
MySQL、PostgreSQL、SQL Serverなどでは使えますが、初心者はLEFT JOINだけを使えば十分です。
| 結合方法 | 表示されるデータ | 使用頻度 |
|---|---|---|
| INNER JOIN | 両方にあるデータだけ | ★★★★☆ |
| LEFT JOIN | 左側は全て、右側は一致するもの | ★★★★★ |
| RIGHT JOIN | 右側は全て、左側は一致するもの | ★☆☆☆☆(使わない) |
| FULL OUTER JOIN | 両方の全データ | ★☆☆☆☆(SQLiteでは不可) |
📝 Step 11 のまとめ
| 学んだこと | 内容 |
|---|---|
| INNER JOINの課題 | マッチしないデータが表示されない |
| LEFT JOIN | 左側のテーブルは全て表示される |
| NULLの発生 | マッチしない場合、右側の列がNULLになる |
| IS NULL | NULLかどうかをチェックする |
| COALESCE | NULLを別の値(0など)に変換する |
| 複数テーブルのLEFT JOIN | 3つ以上のテーブルもLEFT JOINで繋げる |
SELECT 列名 FROM テーブル1 AS t1 LEFT JOIN テーブル2 AS t2 ON t1.共通列 = t2.共通列;
LEFT JOINで全データを取得できるようになりました!
次のStep 12では、データの挿入(INSERT)を学びます。新しいデータをテーブルに追加する方法を学びます。
📝 練習問題
LEFT JOINを使いこなせるように練習しましょう!
全顧客の注文状況
顧客テーブルと注文テーブルをLEFT JOINで結合して、全顧客の顧客名と注文IDを表示してください。
※横にスクロールできます
解説:LEFT JOINで全顧客を表示します。注文がない顧客は注文IDがNULLになります。
全商品の注文状況
商品テーブルと注文テーブルをLEFT JOINで結合して、全商品の商品名と注文IDを表示してください。
※横にスクロールできます
解説:商品テーブルを左側に置くことで、全商品が表示されます。
まだ注文していない顧客
まだ一度も注文していない顧客の顧客名と都道府県を表示してください。
※横にスクロールできます
解説:LEFT JOINでNULLが発生した行を、WHERE句で絞り込みます。
全顧客の注文件数
全顧客の顧客名と注文件数を表示してください。注文していない顧客は0件と表示されるようにしてください。
※横にスクロールできます
解説:COUNT(o.注文ID)はNULLを数えないので、注文がない顧客は0になります。
全顧客の購入数量合計
全顧客の顧客名と購入数量合計を表示してください。購入していない顧客は0と表示されるようにしてください。
※横にスクロールできます
解説:COALESCE()でNULLを0に変換します。
全商品の販売数量
全商品の商品名と販売数量合計を表示してください。まだ売れていない商品は0と表示されるようにしてください。販売数量の多い順に並べてください。
※横にスクロールできます
解説:LEFT JOINで全商品を含め、COALESCE()でNULLを0に変換します。
3テーブルのLEFT JOIN
全顧客について、顧客名、注文件数、購入金額(価格×数量の合計)を表示してください。購入していない顧客は0と表示してください。
※横にスクロールできます
解説:3テーブルをLEFT JOINで結合し、COALESCE()でNULLを0に変換します。
顧客のランク分け
全顧客を購入金額でランク分けしてください。1000円以上=「A」、500円以上=「B」、1円以上=「C」、0円=「D」として、顧客名、購入金額、ランクを表示してください。
※横にスクロールできます
解説:CASE式で購入金額に応じてランクを付けます。
❓ よくある質問
Q1: LEFT JOINとINNER JOINのどちらを使うべきですか?
目的によります。「全件を見たい」ならLEFT JOIN、「関連があるものだけ」ならINNER JOINです。
迷ったら、まずLEFT JOINを試して、NULLが邪魔ならINNER JOINに変更しましょう。
Q2: NULLのチェックで「= NULL」が使えないのはなぜ?
NULLは「値がない」という特別な状態なので、等号(=)では比較できません。
必ずIS NULLまたはIS NOT NULLを使います。
Q3: COALESCE()とは何ですか?
NULLを別の値に置き換える関数です。
COALESCE(列名, 0)で、NULLの場合は0に変換されます。
Q4: LEFT JOINで複数回マッチする場合は?
全てのマッチが表示されます。例えば、1人の顧客が3件の注文をしている場合、その顧客の行が3行表示されます。
GROUP BYで集計すれば、1行にまとめられます。
Q5: 3つ以上のテーブルをLEFT JOINする順番は?
メインのテーブルを最初(FROM)に置き、そこから順番にLEFT JOINします。
例えば、顧客がメインならFROM 顧客 LEFT JOIN 注文 LEFT JOIN 商品のようにします。
Q6: RIGHT JOINは使わなくていいですか?
はい、使わなくて大丈夫です。LEFT JOINでテーブルの順番を入れ替えれば同じことができます。
LEFT JOINだけ覚えれば十分です!
学習メモ
SQL基礎 - Step 11