🔗 Step 10: テーブルの結合入門(INNER JOIN)
複数のテーブルを繋いでデータを取得しよう!
- なぜテーブルを結合する必要があるのか
- 主キーと外部キーの理解
- INNER JOINで2つのテーブルを繋ぐ
- エイリアス(別名)の使い方
- JOINとWHERE句の組み合わせ
- JOINとGROUP BYの組み合わせ
- 3つのテーブルを結合する方法
🎯 1. なぜテーブルを結合する必要があるの?
1-1. 実際のデータベースは複数のテーブルに分かれている
今まで学んできたのは「1つのテーブル」を操作する方法でした。
でも、実際のデータベースでは、データを複数のテーブルに分けて保存します。
- 顧客テーブル:顧客の名前、住所、メールアドレスなど
- 商品テーブル:商品の名前、価格、在庫数など
- 注文テーブル:誰が、いつ、何を注文したかの記録
「なぜ分けるの?1つのテーブルにまとめた方が簡単じゃない?」と思うかもしれません。でも、分けることには重要な理由があります。
1-2. 1つのテーブルにまとめると何が問題か
もし、注文情報を1つのテーブルにまとめると、こうなります:
| 注文ID | 顧客名 | 顧客住所 | 商品名 | 商品価格 | 数量 |
|---|---|---|---|---|---|
| 1 | 田中太郎 | 東京都新宿区… | りんご | 150 | 3 |
| 2 | 田中太郎 | 東京都新宿区… | みかん | 100 | 5 |
| 3 | 佐藤花子 | 大阪府大阪市… | りんご | 150 | 2 |
問題が見えますか?
- 「田中太郎」の住所が2回出てくる → 同じ情報の繰り返しで無駄
- 「りんご」の価格が2回出てくる → 同じ情報の繰り返しで無駄
- 住所を変更したいとき、全ての行を更新する必要がある → 更新漏れの危険
- 価格を変更したいとき、全ての行を更新する必要がある → データの不整合が起きやすい
1-3. 正しい設計:テーブルを分ける
データを適切に分けると、こうなります:
| 顧客ID | 顧客名 | 住所 |
|---|---|---|
| 1 | 田中太郎 | 東京都新宿区… |
| 2 | 佐藤花子 | 大阪府大阪市… |
| 商品ID | 商品名 | 価格 |
|---|---|---|
| 101 | りんご | 150 |
| 102 | みかん | 100 |
| 注文ID | 顧客ID | 商品ID | 数量 |
|---|---|---|---|
| 1 | 1 | 101 | 3 |
| 2 | 1 | 102 | 5 |
| 3 | 2 | 101 | 2 |
こうすれば、「田中太郎」の住所は1箇所だけ、「りんご」の価格も1箇所だけになります。
でも、「注文1の顧客名は?」「注文1の商品名は?」を知りたいときは、テーブルを結合して情報を繋げる必要があります。
- データの重複を防ぐ → 保存容量の節約
- 更新が簡単 → 1箇所変えればOK
- データの整合性を保てる → 不整合が起きにくい
- 柔軟にデータを取得できる → 必要な情報だけを組み合わせられる
🔑 2. 主キーと外部キー
2-1. 主キー(Primary Key)とは
主キーは、テーブルの各行を一意に識別するための列です。
例えば、「顧客ID」は顧客テーブルの主キーです。顧客ID=1なら、必ず「田中太郎」を指します。
- 重複しない → 同じ値が2つ以上存在しない
- NULLにならない → 必ず値がある
- 各テーブルに1つ → 複数の列で構成することもある
2-2. 外部キー(Foreign Key)とは
外部キーは、他のテーブルの主キーを参照する列です。
テーブル同士を繋ぐ「橋渡し」の役割をします。
| テーブル | 主キー | 外部キー |
|---|---|---|
| 顧客テーブル | 顧客ID | なし |
| 商品テーブル | 商品ID | なし |
| 注文テーブル | 注文ID | 顧客ID、商品ID |
注文テーブルの「顧客ID」は、顧客テーブルの「顧客ID」を参照しています。
外部キーは「この注文は顧客1の注文だよ」「この注文は商品101の注文だよ」というリンクの役割をします。
このリンクを使って、テーブルを結合できます!
📊 3. 練習用テーブルの準備
3-1. テーブルを作成する
今回は「顧客」「商品」「注文」の3つのテーブルを使います。
ステップ1:顧客テーブルを作成
※横にスクロールできます
ステップ2:顧客データを追加
※横にスクロールできます
ステップ3:商品テーブルを作成
※横にスクロールできます
ステップ4:商品データを追加
※横にスクロールできます
ステップ5:注文テーブルを作成
※横にスクロールできます
ステップ6:注文データを追加
※横にスクロールできます
3-2. 作成したテーブルの内容
| 顧客ID(主キー) | 顧客名 | 都道府県 |
|---|---|---|
| 1 | 田中太郎 | 東京都 |
| 2 | 佐藤花子 | 大阪府 |
| 3 | 鈴木次郎 | 神奈川県 |
| 4 | 高橋美咲 | 福岡県 |
| 商品ID(主キー) | 商品名 | 価格 | カテゴリ |
|---|---|---|---|
| 101 | りんご | 150 | 果物 |
| 102 | みかん | 100 | 果物 |
| 103 | バナナ | 120 | 果物 |
| 104 | オレンジジュース | 160 | 飲料 |
| 105 | お茶 | 120 | 飲料 |
| 注文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 |
| 7 | 3 | 101 | 1 | 2024-11-15 |
| 8 | 4 | 102 | 3 | 2024-11-18 |
注文テーブルの「顧客ID」は顧客テーブルを参照し、「商品ID」は商品テーブルを参照しています。
🔗 4. INNER JOINの基本
4-1. INNER JOINとは?
INNER JOIN(インナー ジョイン)は、2つのテーブルを繋いで、両方に存在するデータだけを取得する方法です。
英語で「JOIN」は「結合する」、「INNER」は「内側の」という意味です。両方のテーブルの「内側」、つまり共通するデータだけを取得します。
4-2. INNER JOINの基本構文
SELECT 列名 FROM テーブル1 INNER JOIN テーブル2 ON テーブル1.共通列 = テーブル2.共通列;
| 部分 | 意味 | なぜ必要? |
|---|---|---|
FROM テーブル1 |
最初のテーブルを指定 | 結合の起点となるテーブル |
INNER JOIN テーブル2 |
結合するテーブルを指定 | 繋げたいテーブルを指定 |
ON 条件 |
どの列で繋ぐかを指定 | テーブル同士の関連を示す |
4-3. 最初のJOIN:注文と顧客を繋ぐ
注文テーブルと顧客テーブルを結合して、「注文情報と顧客名」を一緒に表示してみましょう。
※横にスクロールできます
| 部分 | 意味 |
|---|---|
FROM 注文 |
注文テーブルを起点にする |
INNER JOIN 顧客 |
顧客テーブルと結合する |
ON 注文.顧客ID = 顧客.顧客ID |
顧客IDが一致するデータを繋げる |
注文.注文ID |
注文テーブルの注文ID列 |
顧客.顧客名 |
顧客テーブルの顧客名列 |
| 注文ID | 顧客名 | 数量 | 注文日 |
|---|---|---|---|
| 1 | 田中太郎 | 3 | 2024-11-01 |
| 2 | 田中太郎 | 5 | 2024-11-03 |
| 3 | 佐藤花子 | 2 | 2024-11-05 |
| 4 | 佐藤花子 | 4 | 2024-11-08 |
| 5 | 鈴木次郎 | 6 | 2024-11-10 |
| 6 | 田中太郎 | 2 | 2024-11-12 |
| 7 | 鈴木次郎 | 1 | 2024-11-15 |
| 8 | 高橋美咲 | 3 | 2024-11-18 |
注文テーブルの「顧客ID=1」が、顧客テーブルの「田中太郎」と紐づいて表示されました!
4-4. JOINの仕組みを理解する
- FROM:最初のテーブル(注文)を読み込む
- INNER JOIN:2番目のテーブル(顧客)を指定
- ON:どの列で繋ぐかを指定(顧客ID)
- マッチング:注文.顧客ID = 顧客.顧客ID が一致する行を探す
- 結合:一致した行を1行にまとめる
- SELECT:指定した列だけを表示
4-5. エイリアス(別名)でテーブル名を短くする
テーブル名が長いと、SQLが読みにくくなります。ASを使って短い別名(エイリアス)をつけましょう。
※横にスクロールできます
注文 AS o→ 注文テーブルを「o」という名前で呼べるようにする顧客 AS c→ 顧客テーブルを「c」という名前で呼べるようにするo.注文ID→ 注文テーブルの注文ID(oは注文の略)c.顧客名→ 顧客テーブルの顧客名(cは顧客の略)
ASは省略できます:FROM 注文 oと書いても同じです。
両方のテーブルに「顧客ID」という列があります。このような場合、どちらのテーブルの列かを明示しないとエラーになります。
- ❌
SELECT 顧客ID→ エラー(どっちの顧客ID?) - ✅
SELECT o.顧客ID→ OK(注文テーブルの顧客ID) - ✅
SELECT c.顧客ID→ OK(顧客テーブルの顧客ID)
🔍 5. JOINとWHERE句の組み合わせ
5-1. 結合した後に絞り込む
JOINで結合した後、WHERE句で条件を指定して絞り込むことができます。
例1:東京都の顧客の注文だけを表示
※横にスクロールできます
- FROM + INNER JOIN:注文テーブルと顧客テーブルを結合
- ON:顧客IDが一致するデータを繋げる
- WHERE:都道府県が「東京都」のデータだけに絞り込む
- SELECT:指定した列を表示
| 注文ID | 顧客名 | 都道府県 | 数量 | 注文日 |
|---|---|---|---|---|
| 1 | 田中太郎 | 東京都 | 3 | 2024-11-01 |
| 2 | 田中太郎 | 東京都 | 5 | 2024-11-03 |
| 6 | 田中太郎 | 東京都 | 2 | 2024-11-12 |
田中太郎さん(東京都)の注文だけが表示されました。
5-2. 複数の条件を組み合わせる
例2:東京都の顧客で、数量が3以上の注文
※横にスクロールできます
| 注文ID | 顧客名 | 数量 | 注文日 |
|---|---|---|---|
| 1 | 田中太郎 | 3 | 2024-11-01 |
| 2 | 田中太郎 | 5 | 2024-11-03 |
📊 6. JOINとGROUP BYの組み合わせ
6-1. 結合してから集計する
JOINとGROUP BYを組み合わせると、複数のテーブルのデータを集計できます。
例1:顧客ごとの注文件数
※横にスクロールできます
- INNER JOIN:注文テーブルと顧客テーブルを結合
- GROUP BY c.顧客ID, c.顧客名:顧客ごとにグループ化
- COUNT(*):各顧客の注文件数を数える
| 顧客名 | 注文件数 |
|---|---|
| 田中太郎 | 3 |
| 佐藤花子 | 2 |
| 鈴木次郎 | 2 |
| 高橋美咲 | 1 |
6-2. 顧客ごとの購入数量合計
※横にスクロールできます
| 顧客名 | 注文件数 | 購入数量合計 |
|---|---|---|
| 田中太郎 | 3 | 10 |
| 鈴木次郎 | 2 | 7 |
| 佐藤花子 | 2 | 6 |
| 高橋美咲 | 1 | 3 |
田中太郎さんが最も多く購入しています(合計10個)。
6-3. 都道府県ごとの注文統計
※横にスクロールできます
| 都道府県 | 注文件数 | 数量合計 |
|---|---|---|
| 東京都 | 3 | 10 |
| 神奈川県 | 2 | 7 |
| 大阪府 | 2 | 6 |
| 福岡県 | 1 | 3 |
🛍️ 7. 3つのテーブルを結合する
7-1. 注文に商品情報も追加する
注文テーブルには「商品ID」しかありません。商品名や価格を表示するには、商品テーブルも結合する必要があります。
まずは注文テーブルと商品テーブルだけを結合してみましょう。
※横にスクロールできます
| 注文ID | 商品名 | 価格 | 数量 | 注文日 |
|---|---|---|---|---|
| 1 | りんご | 150 | 3 | 2024-11-01 |
| 2 | みかん | 100 | 5 | 2024-11-03 |
| 3 | りんご | 150 | 2 | 2024-11-05 |
(以下省略)商品名と価格が表示されるようになりました。
7-2. 顧客情報と商品情報の両方を追加する
INNER JOINを2回使って、3つのテーブルを結合します。
※横にスクロールできます
- FROM 注文 AS o:注文テーブルを起点にする
- INNER JOIN 顧客 AS c ON o.顧客ID = c.顧客ID:顧客テーブルと結合
- INNER JOIN 商品 AS p ON o.商品ID = p.商品ID:さらに商品テーブルと結合
- p.価格 * o.数量 AS 小計:価格×数量を計算して「小計」と表示
| 注文ID | 顧客名 | 商品名 | 価格 | 数量 | 小計 | 注文日 |
|---|---|---|---|---|---|---|
| 1 | 田中太郎 | りんご | 150 | 3 | 450 | 2024-11-01 |
| 2 | 田中太郎 | みかん | 100 | 5 | 500 | 2024-11-03 |
| 3 | 佐藤花子 | りんご | 150 | 2 | 300 | 2024-11-05 |
| 4 | 佐藤花子 | オレンジジュース | 160 | 4 | 640 | 2024-11-08 |
| 5 | 鈴木次郎 | バナナ | 120 | 6 | 720 | 2024-11-10 |
| 6 | 田中太郎 | お茶 | 120 | 2 | 240 | 2024-11-12 |
| 7 | 鈴木次郎 | りんご | 150 | 1 | 150 | 2024-11-15 |
| 8 | 高橋美咲 | みかん | 100 | 3 | 300 | 2024-11-18 |
これで注文明細表のような形になりました!顧客名、商品名、小計が全て表示されています。
7-3. 3テーブル結合 + GROUP BY で売上分析
例:商品ごとの売上集計
※横にスクロールできます
| 商品名 | カテゴリ | 注文件数 | 販売数量 | 売上合計 |
|---|---|---|---|---|
| りんご | 果物 | 3 | 6 | 900 |
| みかん | 果物 | 2 | 8 | 800 |
| バナナ | 果物 | 1 | 6 | 720 |
| オレンジジュース | 飲料 | 1 | 4 | 640 |
| お茶 | 飲料 | 1 | 2 | 240 |
りんごが最も売上が高いことがわかります。
📝 Step 10 のまとめ
| 学んだこと | 内容 |
|---|---|
| テーブルを分ける理由 | データの重複を防ぎ、更新を簡単にするため |
| 主キー | 各行を一意に識別するID(重複しない、NULLにならない) |
| 外部キー | 他のテーブルの主キーを参照する列(テーブル同士を繋ぐ) |
| INNER JOIN | 両方のテーブルに存在するデータだけを結合 |
| エイリアス | テーブル名に短い別名をつける(AS o など) |
| JOIN + WHERE | 結合した後に条件で絞り込む |
| JOIN + GROUP BY | 結合した後にグループ化して集計 |
| 3テーブル結合 | INNER JOINを2回使って3つのテーブルを結合 |
SELECT
t1.列名,
t2.列名
FROM テーブル1 AS t1
INNER JOIN テーブル2 AS t2
ON t1.共通列 = t2.共通列;
INNER JOINでテーブルを結合できるようになりました!
次のStep 11では、LEFT JOIN(左外部結合)など、様々な結合方法を学びます。INNER JOINでは取得できない「片方のテーブルにしかないデータ」も取得できるようになります。
📝 練習問題
INNER JOINを使いこなせるように練習しましょう!
基本的なJOIN
注文テーブルと顧客テーブルを結合して、注文ID、顧客名、数量を表示してください。
※横にスクロールできます
解説:顧客IDで2つのテーブルを結合します。エイリアス(o、c)を使うとコードが読みやすくなります。
商品情報と注文
注文テーブルと商品テーブルを結合して、注文ID、商品名、数量を表示してください。
※横にスクロールできます
解説:商品IDで結合します。pはproduct(商品)の略です。
列名に別名をつける
注文テーブルと顧客テーブルを結合して、注文ID、顧客名、数量、注文日を表示してください。列名は日本語(「注文番号」「お客様名」「購入数」「購入日」)にしてください。
※横にスクロールできます
解説:ASで列に別名をつけます。
JOINとWHERE
注文テーブルと顧客テーブルを結合して、大阪府の顧客の注文だけを表示してください。
※横にスクロールできます
解説:結合した後、WHERE句で絞り込みます。
数量で絞り込み
注文テーブルと顧客テーブルを結合して、数量が3以上の注文だけを表示してください。数量の多い順に並べてください。
※横にスクロールできます
解説:WHERE句で数量を絞り込み、ORDER BYで並び替えます。
顧客ごとの注文件数
注文テーブルと顧客テーブルを結合して、顧客ごとの注文件数を表示してください。
※横にスクロールできます
解説:結合してからGROUP BYで集計します。
顧客ごとの購入数量合計
注文テーブルと顧客テーブルを結合して、顧客ごとの注文件数と購入数量合計を表示してください。購入数量の多い順に並べてください。
※横にスクロールできます
解説:GROUP BYで集計し、ORDER BYで並び替えます。
3テーブルの結合
注文、顧客、商品の3つのテーブルを結合して、注文ID、顧客名、商品名、数量を表示してください。
※横にスクロールできます
解説:INNER JOINを2回使って3つのテーブルを結合します。
小計の計算
注文、顧客、商品の3つのテーブルを結合して、注文ID、顧客名、商品名、価格、数量、小計(価格×数量)を表示してください。
※横にスクロールできます
解説:価格と数量を掛けて小計を計算します。
商品別の売上集計
注文テーブルと商品テーブルを結合して、商品ごとの注文件数、販売数量、売上合計を表示してください。売上合計の多い順に並べてください。
※横にスクロールできます
解説:商品でグループ化して、売上を集計します。
カテゴリ別の売上
注文テーブルと商品テーブルを結合して、カテゴリごとの注文件数と売上合計を表示してください。
※横にスクロールできます
解説:カテゴリでグループ化して集計します。
総合問題:顧客ごとの購入金額
注文、顧客、商品の3つのテーブルを結合して、顧客ごとの注文件数、購入数量、購入金額(売上合計)を表示してください。購入金額の多い順に並べてください。
※横にスクロールできます
解説:3テーブルを結合し、顧客ごとに集計する総合問題です。
❓ よくある質問
Q1: INNER JOINとJOINの違いは?
同じです!JOINと書いてもINNER JOINと書いても同じ意味です。
ただし、「INNER」と明示的に書いた方が、「両方のテーブルに存在するデータだけを取得する」という意図が明確になります。
Q2: エイリアス(AS)は省略できますか?
はい、省略できます。FROM 注文 AS oはFROM 注文 oと書いても同じです。
ただし、ASをつけた方が「別名をつけている」ことが明確になります。
Q3: どちらのテーブルをFROMに書くべきですか?
メインとなるテーブルをFROMに書くのが一般的です。例えば、注文データを中心に見たい場合はFROM 注文とします。
INNER JOINの場合、結果は同じなので、どちらでもOKです。
Q4: 4つ以上のテーブルも結合できますか?
はい、できます!必要なだけINNER JOINを追加すればOKです。
ただし、テーブルが増えると複雑になるので、本当に必要かどうか検討しましょう。
Q5: 同じ名前の列がある場合はどうすればいいですか?
必ずテーブル名(またはエイリアス)をつけて区別します。例えば、両方のテーブルに「顧客ID」がある場合:
o.顧客ID→ 注文テーブルの顧客IDc.顧客ID→ 顧客テーブルの顧客ID
Q6: ON句に複数の条件は書けますか?
はい、書けます。ANDで複数の条件を繋げます:
ON o.顧客ID = c.顧客ID AND o.店舗ID = c.店舗ID
学習メモ
SQL基礎 - Step 10