テーブルを結合する — JOIN
なぜ JOIN が必要か
リレーショナルデータベースでは、データを正規化して複数のテーブルに分けて管理します。たとえば、注文情報にユーザーの名前をそのまま保存するのではなく、user_id だけを持ち、ユーザー情報は users テーブルから引いてくる構造にします。
これにより重複を排除し、データの一貫性を保てますが、取得時には複数テーブルを組み合わせる必要があります。これが JOIN? 複数のテーブルを結合して一つの結果セットにする操作。INNER JOIN(両方に存在する行のみ)・LEFT JOIN(左テーブルの全行 + 一致した右テーブル)などがある。 です。
サンプルテーブルを用意する
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE orders (
id INT NOT NULL AUTO_INCREMENT,
user_id INT,
product VARCHAR(200) NOT NULL,
total DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
INSERT INTO users (name) VALUES ('田中 太郎'), ('佐藤 花子'), ('鈴木 一郎'), ('高橋 美咲');
INSERT INTO orders (user_id, product, total) VALUES
(1, 'ノートPC', 89800.00),
(1, 'マウス', 3200.00),
(2, 'キーボード', 12000.00),
(3, 'モニター', 45000.00),
(NULL, 'ケーブル', 800.00); -- user_idがNULLの注文
INNER JOIN — 一致する行のみ取得
INNER JOIN? 結合条件が一致する行だけを返すJOIN。両テーブルに対応するデータが存在する場合のみ結果に含まれる。最もよく使われる結合方法。 は、両方のテーブルで結合条件が一致する行だけを返します。
SELECT
users.name,
orders.product,
orders.total
FROM orders
INNER JOIN users ON orders.user_id = users.id;
+------------+--------------+----------+
| name | product | total |
+------------+--------------+----------+
| 田中 太郎 | ノートPC | 89800.00 |
| 田中 太郎 | マウス | 3200.00 |
| 佐藤 花子 | キーボード | 12000.00 |
| 鈴木 一郎 | モニター | 45000.00 |
+------------+--------------+----------+
user_id = NULL の注文と、注文のない「高橋 美咲」は結果に含まれません。
LEFT JOIN — 左テーブルの全行を含む
LEFT JOIN? 左テーブルの全行を返し、右テーブルに一致するデータがない場合はNULLで補うJOIN。「注文がないユーザーも含めて一覧表示したい」といった用途に使う。 は、左側(FROM)のテーブルの全行を返します。右側に一致するデータがない場合は NULL で補完されます。
SELECT
users.name,
orders.product,
orders.total
FROM users
LEFT JOIN orders ON orders.user_id = users.id;
+------------+--------------+----------+
| name | product | total |
+------------+--------------+----------+
| 田中 太郎 | ノートPC | 89800.00 |
| 田中 太郎 | マウス | 3200.00 |
| 佐藤 花子 | キーボード | 12000.00 |
| 鈴木 一郎 | モニター | 45000.00 |
| 高橋 美咲 | NULL | NULL |
+------------+--------------+----------+
「注文をしたことがないユーザー」を探したいときは、LEFT JOINのNULLを活用します。
-- 一度も注文していないユーザーを抽出
SELECT users.name
FROM users
LEFT JOIN orders ON orders.user_id = users.id
WHERE orders.id IS NULL;
エイリアス(AS)の使い方
テーブル名やカラム名に別名をつけることで、クエリを簡潔に書けます。
-- テーブルにエイリアスをつける
SELECT
u.name AS ユーザー名,
o.product AS 商品名,
o.total AS 金額
FROM orders AS o
INNER JOIN users AS u ON o.user_id = u.id
ORDER BY o.total DESC;
AS は省略することもできます(orders o と書ける)が、明示した方が読みやすいです。
複数テーブルの JOIN
3つ以上のテーブルをJOINすることもできます。
-- categoriesテーブルも追加する例
CREATE TABLE categories (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE orders ADD COLUMN category_id INT;
ALTER TABLE orders ADD FOREIGN KEY (category_id) REFERENCES categories(id);
-- 3テーブルをJOIN
SELECT
u.name AS ユーザー名,
o.product AS 商品名,
c.name AS カテゴリ,
o.total AS 金額
FROM orders AS o
INNER JOIN users AS u ON o.user_id = u.id
INNER JOIN categories AS c ON o.category_id = c.id
ORDER BY o.total DESC;
ON 句と WHERE 句の違い
JOINの条件は ON 句に、絞り込み条件は WHERE 句に書くのが基本ですが、INNER JOINでは結果が同じになる場合があります。LEFT JOINでは挙動が異なります。
-- ❌ LEFT JOINでWHEREに書くと、結果がINNER JOINと同じになる
SELECT u.name, o.product
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id
WHERE o.total > 10000; -- NULLの行が除外されてしまう
-- ✅ LEFT JOINでの絞り込みはON句に書く
SELECT u.name, o.product
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id AND o.total > 10000;
まとめ
- JOIN は複数テーブルのデータを結合して取得する仕組み
INNER JOIN: 両方のテーブルで一致する行のみ返すLEFT JOIN: 左テーブルの全行を返し、右テーブルに一致がなければ NULL- エイリアス(
AS)でクエリを短くできる - LEFT JOINの絞り込みは
WHEREでなくON句に書く
次回はデータを集計する GROUP BY と集計関数を学びます。