INNER JOIN・LEFT JOIN・RIGHT JOINの違いと使い分け(MySQL実例つき)

MacBook Pro with images of computer language codes SQL

INNER JOIN は、両方のテーブルに相手がいる行だけを返します。LEFT JOIN は左のテーブル(FROM のすぐあと)の行をすべて残し、右に相手がいなければ右の列を NULL で埋めます。RIGHT JOIN はその左右を逆にしたもので、テーブルの順番を入れ替えれば LEFT JOIN で書けます。

迷ったら「相手がいない行も結果に残したいか」で選んでください。残したいなら LEFT JOIN、いらないなら INNER JOIN です。違いを先に表にまとめ、そのあと会員と注文のテーブルで実際の結果を見ていきます(MySQL 8.0)。

3つのJOINの違い(早見表)

種類 返す行 相手がいない行 よく使う場面
INNER JOIN 両方に一致する行だけ 結果から消える 注文と会員の情報をまとめて出す
LEFT JOIN 左の全行 + 右の一致する行 右の列が NULL で残る 注文していない会員も含めた一覧、欠けているデータの確認
RIGHT JOIN 右の全行 + 左の一致する行 左の列が NULL で残る テーブルの順番を入れ替えて LEFT JOIN で書くことが多い

このシナリオで考える

今回は「会員テーブル(members)」と「注文テーブル(orders)」の2テーブルを使います。

CREATE TABLE members (
  id   INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL
);

CREATE TABLE orders (
  id         INT PRIMARY KEY AUTO_INCREMENT,
  member_id  INT,
  amount     INT NOT NULL,
  order_date DATE NOT NULL,
  FOREIGN KEY (member_id) REFERENCES members(id)
);

INSERT INTO members VALUES (1, '田中'), (2, '鈴木'), (3, '佐藤');

INSERT INTO orders VALUES
  (1, 1, 5000, '2026-05-01'),
  (2, 1, 3000, '2026-05-10'),
  (3, 2, 8000, '2026-05-12');

会員は3人ですが、注文レコードは田中さんと鈴木さんの計3件だけです。佐藤さん(id=3)は一度も注文していない状態を前提に進めます。

INNER JOINの基本

INNER JOIN は「両テーブルに一致する行だけ」を返します。ON 句に書いた結合条件を満たさない行は結果から除外されます。

SELECT m.name, o.amount, o.order_date
FROM   members m
INNER JOIN orders o ON m.id = o.member_id;
name amount order_date
田中 5000 2026-05-01
田中 3000 2026-05-10
鈴木 8000 2026-05-12

注文のない佐藤さんは orders テーブルに行がないため、結果に現れません。INNER JOIN は「両方に存在するデータだけ見たい」場面に適しています。注文者の詳細情報を取得する、売上明細を確認するといった用途が典型例です。

JOIN とだけ書いた場合も INNER JOIN と同じ挙動になります。明示的に INNER を書くと意図が明確になり、可読性が上がります。

LEFT JOINで「片側だけ」を取る

LEFT JOIN は「左テーブル(FROM 直後)の全行」を必ず返し、右テーブルに一致する行があれば結合します。一致しない場合は右テーブルの列が NULL になります。

SELECT m.name, o.amount, o.order_date
FROM   members m
LEFT JOIN orders o ON m.id = o.member_id;
name amount order_date
田中 5000 2026-05-01
田中 3000 2026-05-10
鈴木 8000 2026-05-12
佐藤 NULL NULL

佐藤さんの行が amount=NULL、order_date=NULL で追加されました。LEFT JOIN の典型的な使いどころは「注文をしていない会員を一覧で出したい」などの「A はあるが B はない」行を抽出する場面です。

未マッチの行だけを取り出すには、WHERE 句で右テーブルの列が NULL かどうかを確認します。

-- 一度も注文していない会員を抽出
SELECT m.name
FROM   members m
LEFT JOIN orders o ON m.id = o.member_id
WHERE  o.id IS NULL;
name
佐藤

「LEFT JOIN + WHERE IS NULL」は、片方にしかない行を探すときの定番の書き方です。NOT EXISTS や EXCEPT を使うほかの書き方は「SQLで片方のテーブルにしか存在しないデータを抽出する3つの方法」で比べています。

RIGHT JOINと代替の考え方

RIGHT JOIN は LEFT JOIN の反転で、右テーブルの全行を返します。左テーブルに一致しない場合は左側の列が NULL になります。

-- RIGHT JOIN で書く場合
SELECT m.name, o.amount
FROM   members m
RIGHT JOIN orders o ON m.id = o.member_id;

これは次の LEFT JOIN と同じ結果になります。

-- テーブル順を入れ替えて LEFT JOIN で書き直す
SELECT m.name, o.amount
FROM   orders o
LEFT JOIN members m ON o.member_id = m.id;

FROM のテーブル順を入れ替えるだけで RIGHT JOIN は LEFT JOIN に書き換えられます。JOIN の向きがそろっていると読む人が迷わないので、LEFT JOIN だけを使うと決めているチームもあります。

なお、今回のデータでは会員のいない注文がない(外部キーで防いでいる)ため、RIGHT JOIN の結果は INNER JOIN と同じ3行になります。

よくある落とし穴

WHERE 条件で LEFT JOIN が INNER JOIN になる

LEFT JOIN を使っているのに意図せず INNER JOIN と同じ結果になるケースがあります。右テーブルの列を WHERE 句で絞った場合です。

-- NG: WHERE で絞ると佐藤が除外される
SELECT m.name, o.amount
FROM   members m
LEFT JOIN orders o ON m.id = o.member_id
WHERE  o.order_date >= '2026-05-10';

佐藤さんの o.order_date は NULL のため、WHERE 条件を満たさず結果から消えます。全会員を残したまま期間を絞りたいなら、条件を ON 句へ移します。

-- OK: ON 句で絞ると佐藤(NULL 行)が残る
SELECT m.name, o.amount
FROM   members m
LEFT JOIN orders o ON m.id = o.member_id
                  AND o.order_date >= '2026-05-10';
name amount
田中 3000
鈴木 8000
佐藤 NULL

ON 句は「結合するかどうかの条件」、WHERE 句は「結合後の行を絞る条件」です。この区別を押さえるだけで LEFT JOIN 絡みのバグの大半は防げます。

NULL の比較には IS NULL を使う

NULL を比較するとき、= NULL は常に FALSE になります。NULL との比較は必ず IS NULL / IS NOT NULL を使ってください。

-- NG: NULL は = で比較できない(常に FALSE)
WHERE o.id = NULL

-- OK
WHERE o.id IS NULL

まとめ

INNER JOIN・LEFT JOIN・RIGHT JOIN の使い分けは「必要な行の範囲」で決まります。両テーブルに存在するデータだけ見たいなら INNER JOIN、片側の全行を保持したいなら LEFT JOIN を選んでください。LEFT JOIN を使う際は ON 条件と WHERE 条件の違いを意識することで、想定外の行の欠落を防げます。

もっと学ぶなら【PR】

※Amazonのアソシエイトとして、当サイトは適格販売により収入を得ています。

参考リンク

アイキャッチ画像: Photo by Caspar Camille Rubin on Unsplash

タイトルとURLをコピーしました