MySQL JOIN系の基本とその挙動

SQLでよく使われるJOINは、複数テーブルを結合して、共通の情報を一つの結果にまとめるための機能です。

この節では、JOINの種類とその挙動について、基本からまとめていきます。


検証用の一時テーブルを作成する

今回の検証では、セッション内でのみ有効な TEMPORARY TABLE(一時テーブル)を使用します。これにより、環境を汚すことなくテストできます。

-- 一時テーブルがあれば削除
DROP TEMPORARY TABLE IF EXISTS orders;
DROP TEMPORARY TABLE IF EXISTS users;

-- ユーザーテーブル(TEMPORARY)作成
CREATE TEMPORARY TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

-- 注文テーブル(TEMPORARY)作成
CREATE TEMPORARY TABLE orders (
    id INT PRIMARY KEY,
    user_id INT,
    product VARCHAR(100)
);

-- データ挿入(users)
INSERT INTO users (id, name) VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Carol'),
(4, 'David');

-- データ挿入(orders)
INSERT INTO orders (id, user_id, product) VALUES
(1, 1, 'Book'),
(2, 3, 'Laptop'),
(3, 1, 'Pen');
MySQLのクエリ画面
クエリ実行画面

※TablePlusっていうアプリを使ってます

一時テーブルの内容を確認する

正しくデータが挿入されたか、以下のようにそれぞれのテーブルの中身を確認しておきましょう。

users テーブルの確認

SELECT * FROM users;

実行結果

+----+--------+
| id | name   |
+----+--------+
| 1  | Alice  |
| 2  | Bob    |
| 3  | Carol  |
| 4  | David  |
+----+--------+

orders テーブルの確認

SELECT * FROM orders;

実行結果

+----+---------+---------+
| id | user_id | product |
+----+---------+---------+
| 1  | 1       | Book    |
| 2  | 3       | Laptop  |
| 3  | 1       | Pen     |
+----+---------+---------+

この結果から、Alice(ID 1)は2件、Carol(ID 3)は1件の注文を持ち、Bob(ID 2)とDavid(ID 4)は注文がないことが分かります。

JOINの種類

INNER JOIN

  • 両方のテーブルに対応する行がある場合のみを結合
  • 最も基本的なJOIN
  • JOINと書いても使える(業務的にはINNER JOINに統一した方が使いやすいよ…)
  • ユースケース:顧客と注文の対応表
SELECT *
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

実行結果

+----+--------+----+---------+-----------+
| id | name   | id | user_id | product   |
+----+--------+----+---------+-----------+
| 1  | Alice  | 1  | 1       | Book      |
| 1  | Alice  | 3  | 1       | Pen       |
| 3  | Carol  | 2  | 3       | Laptop    |
+----+--------+----+---------+-----------+

LEFT JOIN (LEFT OUTER JOIN)

  • 左側のテーブルはすべて結果に含める
  • 対応する行がなければNULLが入る
  • ユースケース:顧客の注文履歴
SELECT *
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;

実行結果

+----+--------+------+---------+-----------+
| id | name   | id   | user_id | product   |
+----+--------+------+---------+-----------+
| 1  | Alice  | 1    | 1       | Book      |
| 1  | Alice  | 3    | 1       | Pen       |
| 2  | Bob    | NULL | NULL    | NULL      |
| 3  | Carol  | 2    | 3       | Laptop    |
| 4  | David  | NULL | NULL    | NULL      |
+----+--------+------+---------+-----------+

RIGHT JOIN (RIGHT OUTER JOIN)

  • LEFT JOINの逆で、右側のテーブルを保証
  • ユースケース:注文履歴と注文した顧客
  • (ぶっちゃけ可読性が悪くなるのでLEFT JOINだけ使って欲しい)
SELECT *
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;

実行結果

+----+--------+----+---------+-----------+
| id | name   | id | user_id | product   |
+----+--------+----+---------+-----------+
| 1  | Alice  | 1  | 1       | Book      |
| 3  | Carol  | 2  | 3       | Laptop    |
| 1  | Alice  | 3  | 1       | Pen       |
+----+--------+----+---------+-----------+

FULL OUTER JOIN

  • 両方のテーブルのすべての行を結果に含める
  • MySQLは本来サポートしていないため、UNIONなどで表現する必要あり
  • ユースケース:マスターとサブを比較して欠損データがないか確認する
SELECT *
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
UNION
SELECT *
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;

本記事ではJOINの種類と基本動作を確認しました。実行例はぜひ手元で試してみてください。

次回の記事では、LEFT JOINとINNER JOINを使った場合の実行計画(EXPLAIN)の違いと、それがパフォーマンスに与える影響を具体的に検証していきます。

更新情報はX(旧Twitter)で配信中。気になる方はフォローをお願いします!