主キー・外部キー・リレーション: テーブル同士のつながりを読む
Stage 3 — 第1章 | データ分析基礎カリキュラム 推定学習時間:30〜40分 | 難易度:★★☆☆☆
この章で学ぶこと
Stage 1では、1つのテーブルから必要な列や行を取り出す方法を学びました。 しかし実務のデータ分析では、必要な情報が1つのテーブルにまとまっているとは限りません。
ECサイトなら、顧客情報は customers、注文情報は orders、商品情報は products のように分かれて保存されることが多いです。
これらを正しくつなぐために必要なのが、主キー、外部キー、リレーション の考え方です。
この章を終えると、こんなことができるようになります:
- 主キーと外部キーの役割を説明できる
- テーブルを分けて保存する理由を理解できる
- どの列を使ってテーブルをつなぐか判断できる
- JOINを学ぶ前提として、テーブル同士の関係を読める
1. なぜテーブルは分かれているのか
ECサイトの分析では、次のような情報を扱います。
| 知りたいこと | 必要な情報 |
|---|---|
| 誰が購入したか | 顧客情報 |
| いつ注文したか | 注文情報 |
| 何を買ったか | 注文明細 |
| 商品のカテゴリは何か | 商品情報 |
これらをすべて1つの巨大な表に入れると、同じ顧客名や商品名が何度も繰り返されます。 更新ミスも起きやすくなります。
そのため、データベースでは役割ごとにテーブルを分けます。
| テーブル | 1行が表すもの | 主な列 |
|---|---|---|
customers |
顧客1人 | customer_id, customer_name, prefecture |
orders |
注文1件 | order_id, customer_id, order_date, status |
order_items |
注文明細1行 | order_id, product_id, quantity, unit_price |
products |
商品1つ | product_id, product_name, category, price |
分析では、分かれて保存されたテーブルを必要に応じてつなぎます。 そのための基本がJOINです。
2. 主キーは「その行を一意に見分ける列」
主キーは、テーブル内の1行を一意に識別するための列です。 英語では primary key と呼ばれます。
たとえば customers テーブルでは、customer_id が主キーになります。
| customer_id | customer_name | prefecture |
|---|---|---|
| C001 | Aさん | 東京都 |
| C002 | Bさん | 大阪府 |
| C003 | Cさん | 福岡県 |
customer_id が分かれば、どの顧客かを1人に特定できます。
同じ名前の顧客がいても、IDが違えば別の顧客として扱えます。
ECデータでは、次のような列が主キーとして使われます。
| テーブル | 主キーの例 |
|---|---|
customers |
customer_id |
orders |
order_id |
products |
product_id |
主キーは、後でテーブルをつなぐときの基準になります。
3. 外部キーは「別テーブルの行を指す列」
外部キーは、別のテーブルの主キーを参照する列です。 英語では foreign key と呼ばれます。
たとえば orders テーブルには customer_id があります。
| order_id | customer_id | order_date | total_amount |
|---|---|---|---|
| O001 | C001 | 2026-01-05 | 5200 |
| O002 | C002 | 2026-01-06 | 9800 |
| O003 | C001 | 2026-01-10 | 3400 |
ここで orders.customer_id は、customers.customer_id を指しています。
つまり「この注文はどの顧客のものか」を表します。
| 外部キー | 参照先 | 意味 |
|---|---|---|
orders.customer_id |
customers.customer_id |
注文した顧客 |
order_items.order_id |
orders.order_id |
明細が属する注文 |
order_items.product_id |
products.product_id |
明細の商品 |
JOINでは、このような対応する列を使ってテーブルをつなぎます。
4. リレーションはテーブル同士の関係
リレーションは、テーブル同士がどのようにつながっているかを表す考え方です。 ECデータでは、次のような関係があります。
| 関係 | 説明 |
|---|---|
| 顧客と注文 | 1人の顧客は複数の注文を持つことがある |
| 注文と注文明細 | 1つの注文には複数の商品明細が入ることがある |
| 商品と注文明細 | 1つの商品は複数の注文で買われることがある |
たとえば「東京都の顧客が買った商品のカテゴリを知りたい」とします。 この問いに答えるには、1つのテーブルだけでは足りません。
- 顧客の都道府県は
customersにある - 注文日は
ordersにある - 購入数量は
order_itemsにある - 商品カテゴリは
productsにある
このように、分析したい問いが複数テーブルにまたがるときにJOINが必要になります。
5. ER図でテーブル構造を眺める
SQLを書く前に、テーブル同士の関係を ER図(Entity-Relationship Diagram) で眺めると、JOINの理解がかなり楽になります。 ER図は「どのテーブルが、どのキーで、どんな関係で結ばれているか」を示す地図です。
ECデータの基本構造は、次のようなイメージです。
PK: customer_id"] ORDERS["ORDERS
PK: order_id
FK: customer_id"] PRODUCTS["PRODUCTS
PK: product_id"] ORDER_ITEMS["ORDER_ITEMS
PK/FK: order_id
PK/FK: product_id"] CUSTOMERS -->|"1 : N
places"| ORDERS ORDERS -->|"1 : N
contains"| ORDER_ITEMS PRODUCTS -->|"1 : N
included in"| ORDER_ITEMS classDef entity fill:#eff6ff,stroke:#2563eb,color:#1f2937 classDef junction fill:#f0fdf4,stroke:#16a34a,color:#1f2937 class CUSTOMERS,ORDERS,PRODUCTS entity class ORDER_ITEMS junction
このER図では、JOIN経路を読みやすくするため 主キー(PK)と外部キー(FK)だけ を表示しています。注文日、数量、商品カテゴリなどの分析列は各テーブルに存在しますが、関係を結ぶキーとは分けて読みます。
この図を読むときは、次の3点を確認します。
| 確認項目 | 見る場所 | 例 |
|---|---|---|
| 1行の意味 | 各テーブルの説明 | ORDERS の1行 = 注文1件 |
| 主キー(PK) | 行を一意に識別する列 | order_id(order_items は order_id + product_id の複合PK) |
| 外部キー(FK) | 別テーブルへの参照 | orders.customer_id → customers |
order_items では、order_id と product_id が 複合主キー です。
同時に order_id は orders へ、product_id は products への外部キーでもあります。
ER図では両列に PK/FK を付け、2列で複合主キーを作りながら、それぞれが orders と products を参照することを示しています。
ER図があると、「この指標はどのテーブルから作るのか」「このJOINは行数を増やすのか」が先に見えます。 文法を覚える前に、データ構造を読む 習慣をつけることが、実務での分析力につながります。
6. 粒度:1行が何を表すか
粒度(grain) とは、テーブルの1行が何を表すかです。 同じECデータでも、テーブルごとに粒度が違います。
| テーブル | 1行の粒度 | 集計しやすい指標 |
|---|---|---|
customers |
顧客1人 | 登録顧客数 |
orders |
注文1件 | 注文件数、注文金額 |
order_items |
注文明細1行 | 商品別数量、明細売上 |
products |
商品1つ | 商品数、カテゴリ数 |
「顧客ごとの購入回数」を数えたいとき、顧客と注文だけをJOINする場合は次のSQLで足ります。
-- 顧客ごとの購入回数(customers + orders のみ)
SELECT
c.customer_id,
c.customer_name,
COUNT(o.order_id) AS order_count
FROM customers AS c
LEFT JOIN orders AS o
ON c.customer_id = o.customer_id
AND o.status = 'completed'
GROUP BY c.customer_id, c.customer_name;
customers と orders は1対多ですが、JOIN後も 注文1件につき行は1つ です。
LEFT JOIN で注文がない顧客は o.order_id が NULL になり、COUNT(o.order_id) はその行を数えません。
この段階では DISTINCT は不要です。
一方、order_items までJOINすると粒度が明細に落ち、同じ order_id が複数行に増えます。
そのときは COUNT(DISTINCT o.order_id) が必要になります。
-- order_items までJOINすると DISTINCT が必要
SELECT
c.customer_id,
COUNT(DISTINCT o.order_id) AS order_count
FROM customers AS c
LEFT JOIN orders AS o
ON c.customer_id = o.customer_id
LEFT JOIN order_items AS oi
ON o.order_id = oi.order_id
GROUP BY c.customer_id;
orders だけのときは COUNT(o.order_id)、order_items を足したら COUNT(DISTINCT o.order_id) — 粒度が下がったかどうかで数え方が変わります。
集計の前に「今、何の単位で数えているか」を確認しましょう。
7. つなぐ列を間違えると結果も間違う
JOINでは、どの列とどの列を対応させるかが重要です。 たとえば顧客と注文をつなぐなら、次の対応を使います。
SELECT
customers.customer_id,
customers.customer_name,
orders.order_id,
orders.order_date
FROM customers
JOIN orders
ON customers.customer_id = orders.customer_id;
ON customers.customer_id = orders.customer_id が、テーブル同士のつなぎ方です。
列名が同じでも、意味が違う列をつなぐと誤った結果になります。 また、IDではなく名前でつなぐと、同姓同名や表記ゆれで結果がずれることがあります。
分析では、まず次の順番で確認しましょう。
- 各テーブルの1行が何を表すか確認する
- 主キーにあたる列を確認する
- 外部キーにあたる列を確認する
- どの列でJOINするか決める
実務での使いどころ: JOIN前にテーブルの地図を読む
主キーと外部キーは、テーブル同士を安全につなぐための地図です。 分析でJOINを始める前に、どの列が一意で、どの列が別テーブルを参照しているかを確認します。
| テーブル | 主キーの例 | 外部キーの例 |
|---|---|---|
customers |
customer_id |
なし |
orders |
order_id |
customer_id |
order_items |
order_id, product_id |
order_id, product_id |
products |
product_id |
なし |
JOIN条件を間違えると、行数が不自然に増えたり、関係ないデータがつながったりします。 特に、名前が似ている列をなんとなくつなぐのは危険です。
SELECT COUNT(*) AS joined_rows
FROM orders AS o
JOIN customers AS c
ON o.customer_id = c.customer_id;
JOINした後は、行数やサンプル行を確認して、想定した関係になっているかを見ましょう。
ミニ演習
次のJOINで、つなぐ列を考えてください。
- 顧客と注文をつなぐ。
- 注文と注文明細をつなぐ。
- 注文明細と商品をつなぐ。
- JOIN条件を間違えたときに起きる問題を説明する。
まとめ
| 用語 | 意味 | ECデータの例 |
|---|---|---|
| 主キー | そのテーブルの1行を一意に見分ける列 | customers.customer_id |
| 外部キー | 別テーブルの主キーを参照する列 | orders.customer_id |
| リレーション | テーブル同士の関係 | 顧客1人に注文が複数ある |
| 粒度 | 1行が何を表すか | 注文1件、明細1行 |
| ER図 | テーブル構造と関係を示す地図 | 顧客・注文・商品の関係図 |
| JOIN | 関係する列を使ってテーブルをつなぐ操作 | 顧客と注文をつなぐ |
この章のキーメッセージ: JOINは、分かれて保存されたデータを分析目的に合わせて組み合わせるための基本です。SQLを書く前に、主キー・外部キー・1行の意味を確認しましょう。
この章の確認
- 主キーと外部キーの違いを説明してください。
orders.customer_idは、どのテーブルのどの列を参照していると考えられますか?- 「顧客の都道府県別に売上を見たい」とき、どのテーブルをつなぐ必要がありますか?
- テーブルをJOINする前に、なぜ「1行が何を表すか」を確認する必要がありますか?