SQL INNER JOIN: 2 テーブルの一致行を結合

SQL の INNER JOIN では、結合条件が両テーブルで一致する行だけを返します。レコードと参照値を紐付けるような関連データの結合に使い、一致しない行を結果から除外したいときに適しています。結合述語を両側が満たす必要があるため、結合キーが NULL の行や対応行がない行は自動的に除外されます。

関連テーブルを結合する SQL INNER JOIN の例

出力:

ここに出力が表示されます...

出力:

+----------+------------+
| employee | department |
+----------+------------+
| Alma     | 開発       |
| Ben      | 開発       |
| Cara     | 営業       |
+----------+------------+
3 row(s)

この例の仕組み

  1. departments には 3 つの部署、employees には 4 人の従業員を入れ、各行が外部キー dept_id を持ちます。Dan の dept_id は NULL です。
  2. INNER JOIN departments d ON d.id = e.dept_id は、従業員の dept_id と部署の id が一致する行同士を組み合わせます。両側が一致した組だけが残ります。
  3. Dan は dept_id = NULL です。= 演算子はどちらかのオペランドが NULL のとき unknown になるため、Dan はどの部署とも一致せず除外されます。
  4. 人事部(id 3)を参照する従業員はいないため、この部署も結果に現れません。INNER JOIN は両側の不一致行を落とします。

SQL INNER JOIN とは?

INNER JOIN は、結合述語に基づく 2 テーブルの共通部分を返します。論理的には ON 条件が true になる行ペアだけを保持します。物理実行はエンジンやデータ形状により変わります(nested loops、hash join、merge join)が、結果集合に含まれるのは常に一致行だけです。

INNER JOIN と LEFT JOIN の違い

INNER JOINLEFT JOIN
両テーブルで一致した行だけを返す左テーブルの全行を返し、一致がなければ右側列は NULL になる
不一致行は暗黙的に除外される左側の不一致行は保持され、右側の列が NULL で埋まる
一致しないことが不正データを意味する場合に使う一致の有無にかかわらず左側の全レコードを見たい場合に使う

原則: すべての結果行で両テーブルの有効なデータが必要なら INNER JOIN を選びます。右側に一致がなくても行を残したいなら LEFT JOIN に切り替えます。

SQL INNER JOIN でよくある間違い

結合条件の欠落、または常に真の条件

ON 句を省略したり、常に真になる条件を使ったりすると、直積になります。つまり、すべての従業員行がすべての部署行と組み合わされます。

-- 誤り: 直積(4 × 3 で 12 行)
SELECT * FROM employees, departments;

-- 正解: 結合条件を明示する
SELECT * FROM employees e
INNER JOIN departments d ON d.id = e.dept_id;

一意でない結合キーによる行の増殖

INNER JOIN は一致した行ペアごとに 1 行を返します。一意でないキーを持つテーブルに結合すると、左側 1 行が右側の複数行に一致し、結果が意図せず増えることがあります。

INNER JOIN と EXISTS の使い分け

出力に両テーブルの列が必要なら INNER JOIN を使います。関連行が存在するかどうかで絞り込むだけなら EXISTS を使います。サブクエリが複数行に一致する場合、EXISTS は行の増殖を避けられ、クエリプランナは最初の一致で探索を打ち切れることが多いです。

-- EXISTS: 一致する部署がある従業員を 1 行ずつ返す
SELECT e.name FROM employees e
WHERE EXISTS (SELECT 1 FROM departments d WHERE d.id = e.dept_id);

パフォーマンスの注意点

結合述語で使う列(この例では dept_iddepartments.id)にインデックスを作成します。インデックスがないと、エンジンは内側テーブルを何度も走査する可能性があります。大きなテーブルでは EXPLAIN QUERY PLAN で実行計画を確認し、SCAN ではなく USING INDEXSEARCH が出ているかを確認してください。