複数テーブルJOIN: 顧客・注文・商品をつなぐ
Stage 3 — 第5章 | データ分析基礎カリキュラム 推定学習時間:40〜50分 | 難易度:★★★☆☆
この章で学ぶこと
ここまで、2つのテーブルをJOINする方法を学びました。 実務の分析では、3つ以上のテーブルをつないで、ようやく知りたい情報がそろうことがあります。
ECサイトで「どの地域の顧客が、どの商品カテゴリを、どれくらい購入しているか」を見たい場合、顧客・注文・注文明細・商品をつなぐ必要があります。
この章を終えると、こんなことができるようになります:
- 複数テーブルを順番にJOINできる
- 顧客、注文、注文明細、商品を1つの結果につなげられる
- JOINの順番と条件を読み解ける
- 分析目的に合わせて必要な列だけを選べる
1. 分析したい問いから必要なテーブルを決める
複数テーブルJOINでは、いきなりSQLを書き始めるのではなく、まず問いを分解します。
たとえば、次の問いを考えます。
東京都の顧客が購入した商品のカテゴリ別売上を見たい
この問いに必要な情報は、複数のテーブルに分かれています。
| 必要な情報 | テーブル | 列の例 |
|---|---|---|
| 顧客の都道府県 | customers |
customer_id, prefecture |
| 注文の状態 | orders |
order_id, customer_id, status |
| 購入数量と単価 | order_items |
order_id, product_id, quantity, unit_price |
| 商品カテゴリ | products |
product_id, category |
このように、必要な列がどこにあるかを整理すると、JOINの道筋が見えてきます。
2. 顧客から注文へつなぐ
まず、顧客と注文を customer_id でつなぎます。
SELECT
c.customer_id,
c.customer_name,
c.prefecture,
o.order_id,
o.order_date,
o.status
FROM customers AS c
INNER JOIN orders AS o
ON c.customer_id = o.customer_id;
この時点では、「誰がどの注文をしたか」が分かります。 ただし、まだ注文の中身である商品情報は分かりません。
複数テーブルJOINでは、1つずつ情報を足していくと理解しやすくなります。
3. 注文から注文明細へつなぐ
次に、注文と注文明細を order_id でつなぎます。
SELECT
c.customer_id,
c.prefecture,
o.order_id,
o.order_date,
oi.product_id,
oi.quantity,
oi.unit_price
FROM customers AS c
INNER JOIN orders AS o
ON c.customer_id = o.customer_id
INNER JOIN order_items AS oi
ON o.order_id = oi.order_id;
ここまでつなぐと、結果の1行は「注文明細1行」になります。
1つの注文に複数商品が含まれる場合、同じ order_id が複数行に出ます。
この粒度の変化を理解しておくことが、正しい集計につながります。
4. 注文明細から商品へつなぐ
最後に、注文明細と商品を product_id でつなぎます。
SELECT
c.customer_id,
c.prefecture,
o.order_id,
o.order_date,
p.product_name,
p.category,
oi.quantity,
oi.unit_price
FROM customers AS c
INNER JOIN orders AS o
ON c.customer_id = o.customer_id
INNER JOIN order_items AS oi
ON o.order_id = oi.order_id
INNER JOIN products AS p
ON oi.product_id = p.product_id;
これで、顧客属性、注文情報、購入数量、商品カテゴリが1つの結果にそろいました。 この結果をもとに、商品カテゴリ別や地域別の分析ができるようになります。
5. カテゴリ別売上を集計する
複数テーブルをつないだら、分析目的に合わせて集計できます。 次のSQLは、東京都の顧客について、商品カテゴリ別の売上を集計します。
SELECT
p.category,
SUM(oi.quantity * oi.unit_price) AS sales_amount
FROM customers AS c
INNER JOIN orders AS o
ON c.customer_id = o.customer_id
INNER JOIN order_items AS oi
ON o.order_id = oi.order_id
INNER JOIN products AS p
ON oi.product_id = p.product_id
WHERE c.prefecture = '東京都'
AND o.status = 'completed'
GROUP BY p.category
ORDER BY sales_amount DESC;
このSQLでは、売上を orders.total_amount ではなく、明細単位の quantity * unit_price で計算しています。
商品カテゴリ別に見るためには、明細単位で集計する必要があるためです。
6. 複数JOINを書くときの確認ポイント
複数テーブルJOINでは、SQLが長くなります。 長いSQLほど、途中で前提を確認することが大切です。
| 確認ポイント | 例 |
|---|---|
| どのテーブルを基準にするか | 顧客基準か、注文基準か、明細基準か |
| JOIN条件は正しいか | customer_id, order_id, product_id を取り違えていないか |
| 結果の1行は何を表すか | 顧客、注文、明細のどれか |
| 集計列は粒度に合っているか | カテゴリ別なら明細金額を使う |
| 除外条件は明確か | キャンセル注文を含めるか除くか |
最初から完成形を書くのではなく、2テーブルずつJOINして結果を確認しながら進めると、ミスに気づきやすくなります。
7. 分析にJOINが必要な理由
JOINは、単にテーブルを横につなげる構文ではありません。 分析したい問いに必要な情報を、正しい粒度でそろえるための操作です。
たとえば、次のような問いはJOINなしでは答えにくいです。
- 地域別に人気の商品カテゴリを見たい
- 未購入顧客と購入済み顧客を比較したい
- 商品カテゴリ別の売上を注文日ごとに見たい
- 顧客ごとの購入商品数を集計したい
実務では、データは整理のために分かれて保存され、分析では目的に合わせてつなぎ直します。 JOINは、その橋渡しをする基本スキルです。
実務での使いどころ: 問いから必要なテーブルを逆算する
複数テーブルJOINでは、先にJOINを書くのではなく、分析したい問いから必要な情報を逆算します。 たとえば「カテゴリ別売上」を見たいなら、売上金額、商品カテゴリ、注文状態が必要です。
| 必要な情報 | ありそうなテーブル |
|---|---|
| 注文状態 | orders |
| 商品ごとの数量と単価 | order_items |
| 商品カテゴリ | products |
このように分解すると、必要なJOIN経路が見えてきます。
SELECT
p.category,
SUM(oi.quantity * oi.unit_price) AS sales
FROM orders AS o
JOIN order_items AS oi
ON o.order_id = oi.order_id
JOIN products AS p
ON oi.product_id = p.product_id
WHERE o.status = 'completed'
GROUP BY p.category
ORDER BY sales DESC;
複数JOINでは、1つのJOINミスが全体の結果に影響します。 JOINを1つ追加するたびに、行数とサンプルを確認しましょう。
ミニ演習
次の分析に必要なテーブルを考えてください。
- 都道府県別の売上を見たい。
- 商品カテゴリ別の購入者数を見たい。
- 顧客ごとの購入商品数を見たい。
- 複数JOINで行数確認が重要な理由を説明する。
まとめ
| つなぐ関係 | JOIN条件 | 追加できる情報 |
|---|---|---|
| 顧客と注文 | c.customer_id = o.customer_id |
誰が注文したか |
| 注文と注文明細 | o.order_id = oi.order_id |
何個買ったか |
| 注文明細と商品 | oi.product_id = p.product_id |
商品名・カテゴリ |
この章のキーメッセージ: 複数テーブルJOINでは、分析したい問いから必要なテーブルを逆算します。JOIN条件、結果の粒度、集計列の意味を確認しながら、段階的にSQLを組み立てましょう。
この章の確認
- 「地域別の商品カテゴリ売上」を見るために必要な4つのテーブルを挙げてください。
ordersとorder_itemsは、どの列でJOINしますか?- 商品カテゴリ別売上を集計するとき、なぜ
orders.total_amountではなくquantity * unit_priceを使うことがありますか? - 複数テーブルJOINを書く前に、分析したい問いを分解する理由を説明してください。