KAKUTA TECH BLOG

Blog Article

MySQL のテーブル結合(JOIN)を基本から解説

はじめに

MySQL では、複数のテーブルに分かれたデータをまとめて取得したい場面があります。そのときに使用するのが JOIN です。この記事では、users と reports の2つのテーブルを例に、INNER JOIN、LEFT JOIN、RIGHT JOIN の基本的な使い方と違いを解説します。

参考リンク

  • MySQL 8.4 Reference Manual - JOIN Clause
  • MySQL 8.4 Reference Manual - FOREIGN KEY Constraints

JOIN とは

JOIN とは、複数のテーブルを関連付けて、まとめてデータを取得するための仕組みです。データベースでは、ユーザー情報や商品情報、注文情報などを、それぞれ別のテーブルに分けて管理することがあります。そのため、実際にデータを取得するときには、複数のテーブルを組み合わせる必要が出てきます。

たとえば、users テーブルにユーザー情報、reports テーブルに日報を保存しているとします。reports テーブルに user_id を保存しておけば、「この日報はどのユーザーのものなのか」を判断できます。そして、users.id と reports.user_id を条件として指定することで、ユーザー名と日報の内容を一緒に取得できます。

users
┌────┬──────────┐
│ id │ name     │
├────┼──────────┤
│ 1  │ 山田太郎 │
│ 2  │ 佐藤花子 │
│ 3  │ 鈴木一郎 │
└────┴──────────┘
       │
       │ users.id = reports.user_id
       ↓
reports
┌────┬─────────┬─────────┐
│ id │ user_id │ content │
├────┼─────────┼─────────┤
│ 1  │ 1       │ 日報A   │
│ 2  │ 2       │ 日報B   │
└────┴─────────┴─────────┘

JOIN では、このようなテーブル同士の関係を ON 句に指定します。つまり、JOIN を理解するときは「複数のテーブルを結合する構文」だけを見るのではなく、どのテーブルの、どの列同士を関連付けるのかを意識することが重要です。MySQL では ON 句に結合条件を指定して JOIN を記述できます。

サンプルテーブルを作成する

JOIN の動作を確認するために、ここでは users と reports の2つのテーブルを使用します。users にはユーザーの基本情報を保存し、reports にはユーザーが作成した日報を保存します。reports.user_id には、どのユーザーの日報なのかを識別するために users.id と対応する値を保存します。

また、今回のサンプルでは FOREIGN KEY も設定します。FOREIGN KEY は JOIN そのものではなく、関連するテーブル間のデータを参照し、整合性を保つための制約です。MySQL の公式ドキュメントでも、外部キーは親テーブルの値を子テーブルから参照する関係として説明されています。

users テーブルを作成する

まず、ユーザー情報を保存する users テーブルを作成します。id を主キーとして、name、email、age を保存します。email には UNIQUE を指定しているため、同じメールアドレスを複数の行に登録できないようにしています。

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE,
    age INT
);

reports テーブルを作成する

次に、日報を保存する reports テーブルを作成します。user_id が日報を作成したユーザーを表し、report_date に日報の日付、content に日報の内容を保存します。

最後の FOREIGN KEY によって、reports.user_id が users.id を参照することを明示しています。このように関連するテーブルを定義しておくことで、ユーザーと日報の関係をデータベース上でも表現できます。

CREATE TABLE reports (
    id INT PRIMARY KEY,
    user_id INT NOT NULL,
    report_date DATE NOT NULL,
    content TEXT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

サンプルデータを登録する

テーブルを作成したら、ユーザーと日報のデータを登録します。ここでは、4人のユーザーを登録します。ただし、日報は3人分だけ登録します。

あえて1人分の日報を登録しないことで、後ほど INNER JOIN と LEFT JOIN の違いを確認できます。すべてのユーザーに日報が存在すると、INNER JOIN と LEFT JOIN の結果が同じになってしまうためです。

INSERT INTO users (id, name, email, age)
VALUES
    (1, '山田太郎', 'yamada@example.com', 25),
    (2, '佐藤花子', 'sato@example.com', 30),
    (3, '鈴木一郎', 'suzuki@example.com', 28),
    (4, '田中次郎', 'tanaka@example.com', 35);

続いて、3人分の日報を登録します。

INSERT INTO reports (id, user_id, report_date, content)
VALUES
    (1, 1, '2026-09-15', '商品ページを作成しました。'),
    (2, 2, '2026-09-15', 'ログイン機能を実装しました。'),
    (3, 3, '2026-09-15', 'テストを実施しました。');

この状態では、user_id = 4 の田中次郎には対応する日報がありません。この違いが、JOIN の種類によって検索結果にどのような影響を与えるのかを確認するポイントになります。

INNER JOIN で一致するデータを取得する

INNER JOIN は、結合条件に一致するデータだけを取得する JOIN です。つまり、左側と右側のテーブルにそれぞれ対応する行が存在している場合、そのデータを結合して取得します。一方、片方のテーブルにしか存在しないデータは検索結果に含まれません。

今回の例では、users.id と reports.user_id が一致するデータを取得します。そのため、users に登録されていても reports に対応する日報がないユーザーは結果から除外されます。

SELECT
    users.name,
    reports.report_date,
    reports.content
FROM users
INNER JOIN reports
    ON users.id = reports.user_id;

この SQL では、ON users.id = reports.user_id によって結合条件を指定しています。MySQL の公式ドキュメントでも、INNER JOIN は ON 句などの条件を使ってテーブルを結合する構文として説明されています。

INNER JOIN の結果

今回のデータでは、山田太郎、佐藤花子、鈴木一郎の3人に日報があります。そのため、この3人だけが検索結果に表示されます。

name       | report_date | content
-----------+-------------+---------------------------
山田太郎   | 2026-09-15  | 商品ページを作成しました。
佐藤花子   | 2026-09-15  | ログイン機能を実装しました。
鈴木一郎   | 2026-09-15  | テストを実施しました。

田中次郎は users テーブルには存在しますが、対応する reports が存在しないため、検索結果には含まれません。

このように INNER JOIN は、「両方のテーブルに対応するデータが存在するものだけ取得したい」場合に使用すると考えると分かりやすいです。なお、MySQL では JOIN と INNER JOIN は構文上同等として扱われますが、JOIN の種類を明確にするため、学習時には INNER JOIN と書いておくと意図を把握しやすくなります。

LEFT JOIN ですべてのユーザーを取得する

LEFT JOIN は、左側に指定したテーブルの行をすべて残し、右側のテーブルに対応するデータがあれば結合する JOIN です。右側に対応するデータが存在しない場合でも、左側の行は検索結果に残ります。その場合、右側のテーブルにある列には NULL が入ります。

今回の例では、users を左側、reports を右側に指定します。そのため、日報が存在するユーザーだけでなく、日報が存在しないユーザーも結果に含まれます。MySQL の公式ドキュメントでも、LEFT JOIN で右側に一致する行がない場合、右側の列に NULL が入った行が生成されると説明されています。

SELECT
    users.name,
    reports.report_date,
    reports.content
FROM users
LEFT JOIN reports
    ON users.id = reports.user_id;

LEFT JOIN の結果

今回のデータでは、田中次郎に対応する日報がありません。しかし、users が左側に指定されているため、田中次郎も結果に残ります。

name       | report_date | content
-----------+-------------+---------------------------
山田太郎   | 2026-09-15  | 商品ページを作成しました。
佐藤花子   | 2026-09-15  | ログイン機能を実装しました。
鈴木一郎   | 2026-09-15  | テストを実施しました。
田中次郎   | NULL        | NULL

このように、LEFT JOIN では「左側のテーブルを基準にして、右側に対応するデータがなくても残す」という動作になります。ここが INNER JOIN との大きな違いです。

たとえば、「まだ日報を登録していないユーザーを調べたい」という場合にも LEFT JOIN を利用できます。右側の reports.id が NULL になっている行を WHERE 句で絞り込めば、対応する日報がないユーザーだけを取得できます。MySQL 公式ドキュメントにも、このような LEFT JOIN と IS NULL を組み合わせる方法が掲載されています。

SELECT
    users.name
FROM users
LEFT JOIN reports
    ON users.id = reports.user_id
WHERE reports.id IS NULL;

RIGHT JOIN で右側のテーブルを基準にする

RIGHT JOIN は、LEFT JOIN とは反対に、右側に指定したテーブルの行をすべて残す JOIN です。左側のテーブルに対応するデータが存在しない場合でも、右側の行は結果に含まれ、左側の列には NULL が入ります。

たとえば、次の SQL では reports が右側に指定されています。そのため、基準になるのは reports テーブルです。users に対応するデータが存在しない日報があった場合でも、その日報は結果に残ります。

SELECT
    users.name,
    reports.report_date,
    reports.content
FROM users
RIGHT JOIN reports
    ON users.id = reports.user_id;

今回のサンプルでは、すべての日報に対応するユーザーが存在しているため、結果は INNER JOIN と同じになります。これは RIGHT JOIN が正しく動作していないという意味ではなく、今回用意したデータでは「対応するユーザーが存在しない日報」がないためです。

MySQL の公式ドキュメントでは、RIGHT JOIN は LEFT JOIN と同様の仕組みとして説明されています。また、データベース間の移植性を考慮し、RIGHT JOIN より LEFT JOIN を使用することが推奨されています。

JOIN の種類による違いを整理する

INNER JOIN、LEFT JOIN、RIGHT JOIN の違いを理解するときは、構文そのものを暗記するよりも、「どのテーブルのデータを必ず残したいのか」を考えることが重要です。INNER JOIN は左右のテーブルで条件が一致した行だけを取得します。LEFT JOIN は左側のテーブルを基準にしてすべて残し、RIGHT JOIN は右側のテーブルを基準にしてすべて残します。

今回の users と reports の例では、次のように整理できます。

JOIN

残すデータ

対応するデータがない場合

INNER JOIN

一致した行のみ

行を取得しない

LEFT JOIN

左側のテーブルをすべて残す

右側が NULL

RIGHT JOIN

右側のテーブルをすべて残す

左側が NULL

特に重要なのは、LEFT JOIN と RIGHT JOIN の「どちら側を残すのか」という考え方です。JOIN を使うときは、まず「何を基準に検索したいのか」を考え、そのうえで JOIN の種類を選択すると分かりやすくなります。

FOREIGN KEY と JOIN の違い

users.id と reports.user_id のような関連を扱うとき、FOREIGN KEY と JOIN がどちらも登場するため、同じ役割を持つものだと考えてしまうことがあります。しかし、実際には目的が異なります。

FOREIGN KEY は、テーブル間の関連をデータベース上の制約として定義するための仕組みです。今回であれば、reports.user_id が users.id を参照することを定義しています。MySQL では、外部キーによって関連するデータを参照し、テーブル間のデータの整合性を保つことができます。

一方、JOIN は、複数のテーブルに保存されているデータを結合して検索結果を取得するための仕組みです。そのため、FOREIGN KEY が「テーブル同士の関係を定義・管理するもの」、JOIN が「関連するデータを検索するときに使うもの」と考えると、それぞれの役割を整理しやすくなります。

FOREIGN KEY
    ↓
テーブル間の関連や整合性を定義する

JOIN
    ↓
関連するテーブルのデータを取得する

また、JOIN を使用するために必ず FOREIGN KEY が必要というわけではありません。JOIN は ON 句で指定した条件に基づいてテーブルを結合するため、外部キー制約が設定されていないテーブル同士でも JOIN 自体は実行できます。

JOIN を使うときに意識すること

JOIN の構文を覚えるだけでは、実際の SQL でどの JOIN を選べばよいのか迷うことがあります。そのため、まず「どのデータを基準にしたいのか」を考えることが大切です。たとえば、「日報を登録しているユーザーだけ取得したい」のであれば INNER JOIN、「日報の有無に関係なくユーザーをすべて取得したい」のであれば users を左側にした LEFT JOIN が候補になります。

さらに、JOIN では「どの列同士を関連付けるのか」も重要です。今回なら users.id と reports.user_id が対応しています。

ON users.id = reports.user_id

この条件によって、「users の id と reports の user_id が一致する行を関連付ける」という意味になります。

そのため、JOIN を考えるときは、次の3点を順番に整理すると分かりやすくなります。

  1. どのテーブルのデータを取得したいのか
  2. どの列同士を関連付けるのか
  3. 対応するデータがない場合も残したいのか

この3点が決まれば、INNER JOIN と LEFT JOIN などの違いも判断しやすくなります。

まとめ

JOIN は、複数のテーブルに分かれて保存されている関連データを、1つの検索結果として取得するための仕組みです。実際のアプリケーションでは、ユーザー、商品、注文、記事などを別々のテーブルで管理することが多いため、複数のテーブルを組み合わせて検索する JOIN は SQL の基本として重要です。

今回扱った JOIN は、それぞれ次のような特徴があります。

  • INNER JOIN:左右のテーブルで条件が一致する行だけ取得する
  • LEFT JOIN:左側のテーブルをすべて残し、右側に対応するデータがなければ NULL にする
  • RIGHT JOIN:右側のテーブルをすべて残し、左側に対応するデータがなければ NULL にする

また、FOREIGN KEY と JOIN は役割が異なります。FOREIGN KEY はテーブル間の関連やデータの整合性を扱い、JOIN は関連するデータを取得するときに使用します。

JOIN を使うときは構文を丸暗記するのではなく、**「どのテーブルを基準にするのか」「どの列同士を結合するのか」「対応するデータがない場合にどうしたいのか」**を考えることがポイントです。