この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:guest
更新日時:2026-06-11 07:10:02

タイトル: ONとWHEREの違い
SEOタイトル: SQL JOIN の ON と WHERE の違い 完全ガイド(内部結合 / 外部結合 / NULL の扱い / フィルタ順序)

この記事の要点
  • ON結合条件(どの行とどの行を組み合わせるか)を指定する
  • WHERE結合結果に対するフィルタ(できた表のどの行を残すか)を指定する
  • INNER JOIN では結果は同じになりやすいが、OUTER JOIN では大きく違う
  • LEFT JOIN で右側テーブルの条件を WHERE に書くと、NULL 行が消えて事実上 INNER JOIN になる
  • 結合条件は ON、行の絞り込みは WHERE と役割で書き分けるのが基本

結論

SQL で複数のテーブルを結合する際、ONWHERE はどちらも条件を書けますが、役割が違います

  • ON — どの行同士を組み合わせるか(結合条件)
  • WHERE — 結合結果のうちどれを残すか(フィルタ条件)

INNER JOIN ではどちらに書いても結果が同じになるケースが多いですが、LEFT / RIGHT / FULL OUTER JOIN では結果が変わります

サンプルデータ

顧客テーブル customers と注文テーブル orders を例に説明します。

-- customers
id | name
---+-------
 1 | Alice
 2 | Bob
 3 | Carol  (注文なし)

-- orders
id | customer_id | amount | status
---+-------------+--------+--------
10 | 1           | 1000   | paid
11 | 1           |  500   | canceled
12 | 2           | 2000   | paid

INNER JOIN の場合(ほぼ同じ結果)

-- 書き方 A: ON に条件を書く
SELECT c.name, o.amount
  FROM customers c
  JOIN orders    o
    ON o.customer_id = c.id
   AND o.status      = 'paid';

-- 書き方 B: WHERE に条件を書く
SELECT c.name, o.amount
  FROM customers c
  JOIN orders    o
    ON o.customer_id = c.id
 WHERE o.status = 'paid';

INNER JOIN ではどちらも結果は同じです。

nameamount
Alice1000
Bob2000

LEFT JOIN の場合(結果が違う)

ここが ON / WHERE の本質的な違いが出る場面です。

パターン A: ON に書く(LEFT JOIN として正しく動く)

SELECT c.name, o.amount
  FROM customers c
  LEFT JOIN orders o
    ON o.customer_id = c.id
   AND o.status      = 'paid';
nameamount
Alice1000
Bob2000
CarolNULL

Carol は注文がないため、orders 側は NULL のまま残る。これが LEFT JOIN らしい挙動です。

パターン B: WHERE に書く(実質 INNER JOIN になる)

SELECT c.name, o.amount
  FROM customers c
  LEFT JOIN orders o
    ON o.customer_id = c.id
 WHERE o.status = 'paid';
nameamount
Alice1000
Bob2000

Carol は o.status が NULL となり、NULL = 'paid'真にならないため WHERE で消されます。結果として LEFT JOIN を書いたのに INNER JOIN と同じ結果になる、という典型的な落とし穴です。

実行順序のイメージ

SQL は概念的に次の順序で評価されます。

  1. FROM — テーブルを並べる
  2. ON — 結合条件で行を組み合わせる
  3. JOIN タイプ — LEFT / RIGHT なら不一致側に NULL 行を追加
  4. WHERE — 結合結果をフィルタ
  5. GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

つまり、WHERE はすでに NULL 補完が済んだ結果に対して動くので、外側テーブルの条件を WHERE に書くと NULL 行を切り落としてしまうわけです。

書き分けの指針

条件の性質書く場所
結合キーONo.customer_id = c.id
結合先テーブル自身の絞り込み(OUTER JOIN)ONAND o.status = 'paid'
結果セット全体の絞り込みWHEREWHERE c.country = 'JP'
NULL を残したい条件ON同上
NULL を残してはいけない条件WHERE意図的に INNER 化したいとき

INNER JOIN なら気にしなくていい?

結果は同じになりますが、意図を読む人に伝えるため、結合キー / 結合先絞り込みは ON に、結果全体のフィルタは WHERE に分けて書くのが推奨されます。後から OUTER JOIN に変更しても破綻しにくくなります。

OUTER JOIN で WHERE を使いたいケース

「LEFT JOIN したうえで、マッチしなかった行だけを抽出したい」場合は WHERE に NULL 判定を書きます。

-- 注文が 1 件もない顧客を取得
SELECT c.name
  FROM customers c
  LEFT JOIN orders o
    ON o.customer_id = c.id
 WHERE o.id IS NULL;

FAQ

Q: ON に常に 1=1 と書くとどうなる?
A: 全行同士をマッチさせるクロス結合と同等です。デバッグ用途以外には使いません。

Q: 古い書き方 FROM a, b WHERE a.id = b.id はどう違う?
A: 旧来の「カンマ結合」では結合条件もすべて WHERE に書きます。OUTER JOIN は表現できず、SQL-92 の JOIN ... ON 書式が現代の標準です。

Q: 集計関数の条件は WHERE?
A: 集計後の条件は HAVING に書きます(例: HAVING SUM(amount) > 1000)。

関連

  • RDBMS共通 — 親カテゴリ
  • INNER JOIN / LEFT JOIN / RIGHT JOIN / FULL OUTER JOIN
  • WHERE 句 / HAVING 句
  • NULL の評価 / IS NULL / COALESCE
  • サブクエリと EXISTS