LEFT / RIGHT OUTER JOIN の使い方
shain社員
| name | busho_id |
|---|---|
| 中村 | 2 |
| 大野 | NULL |
| … | |
busho部署
| busho_id | busho_name |
|---|---|
| 2 | 開発 |
| 6 | 法務✕ |
| … | |
LEFT JOINつないだ結果
| name | busho_id | busho_name |
|---|---|---|
| 中村 | 2 | 開発 |
| 大野 | NULL | NULL |
| … | ||
- busho_nameのように、右の表の列が左の表にくっつくのが結合です。
- 社員 18 行 → つないだ結果 18 行(行数は変わりません)
- 取り消し線= 相手がいないので結果に出てこない行
- 結果に
NULLが入っている行は、相手がいないまま残った行です。
LEFT OUTER JOIN は「左の表の行を必ず残す」結合です。 相手が見つからなかった行も消さずに残し、相手側の列には NULL を入れます。内部結合で行が消えて困るときに使います。
主要 7 製品で通用 そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server / Oracle Database / IBM Db2
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
01内部結合との違いは「消えるか、残るか」だけ
結論: `LEFT OUTER JOIN` は左の表の行を 1 行も減らしません。
内部結合(INNER JOIN)は、両方の表に相手がいる行だけを返します。相手がいない行は黙って消えます。
外部結合はそこが違います。相手がいなくても左の行は残り、相手側の列だけが `NULL` になります。
OUTER は省略できます。LEFT JOIN と LEFT OUTER JOIN はまったく同じ意味です。
SELECT s.name, b.busho_name何を出すかFROM shain s必ず残す側(左)LEFT JOIN busho b相手がいなくてもよい側(右)ON b.busho_id = s.busho_idどの列どうしが同じかORDER BY s.shain_id並び順
FROM に書いた表が「左」、JOIN に書いた表が「右」です。LEFT は「左を残す」という意味です。
SELECT s.name, b.busho_name
FROM shain s
JOIN busho b ON b.busho_id = s.busho_id
ORDER BY s.shain_id;| name | busho_name |
|---|---|
| 鈴木 | 経営 |
| 佐藤 | 開発 |
| 田中 | 開発 |
| 中村 | 開発 |
| 小林 | 開発 |
(16 行 … うち先頭 5 行を表示)
SELECT s.name, b.busho_name
FROM shain s
LEFT JOIN busho b ON b.busho_id = s.busho_id
ORDER BY s.shain_id;| name | busho_name |
|---|---|
| 鈴木 | 経営 |
| 佐藤 | 開発 |
| 田中 | 開発 |
| 中村 | 開発 |
| 小林 | 開発 |
(18 行 … うち先頭 5 行を表示)
①と②で件数が違います。増えた 1 行が「部署が決まっていない社員」です。
02NULL は「相手がいなかった」という意味になる
外部結合の結果に出てくる NULL には、2 つの意味が混ざります。
- もともとその列が
NULLだった - 相手が見つからなかったので `NULL` が入った
見た目では区別できません。どちらなのかを知りたい場合は、結合キーそのものを見ます。結合キーが NULL なら「相手がいなかった」側です。
この性質を使うと「相手がいない行だけ」を取り出せます。外部結合してから IS NULL で絞るやり方で、実務でよく使います。
SELECT s.name, s.busho_id, b.busho_name
FROM shain s
LEFT JOIN busho b ON b.busho_id = s.busho_id
WHERE b.busho_id IS NULL;| name | busho_id | busho_name |
|---|---|---|
| 渡辺 | NULL | NULL |
| 大野 | NULL | NULL |
(2 行)
結合してから「相手がいなかった行」だけを残す書き方です。
03向きを変えると、残る側が変わる
RIGHT OUTER JOIN は右の表を必ず残します。左右が入れ替わるだけで、考え方は同じです。
実務では `LEFT` に統一するのが一般的です。FROM に書いた表が主役、という読み方が崩れないからです。RIGHT を使いたくなったら、表の順番を入れ替えて LEFT にできないか考えてみてください。
次の例では、社員が 1 人もいない部署を出しています。部署を必ず残したいので、部署を左に置いて LEFT で書いています。
SELECT b.busho_name, s.name
FROM busho b
LEFT JOIN shain s ON s.busho_id = b.busho_id
WHERE s.shain_id IS NULL;| busho_name | name |
|---|---|
| 法務 | NULL |
(1 行)
04⚠️ よくある間違い:WHERE に条件を書くと、外側の行が消える
これが外部結合でいちばん多い事故です。
せっかく LEFT JOIN で残した行が、`WHERE` に右の表の条件を書いた瞬間に消えます。相手がいない行では右の列が NULL になり、NULL を使った比較は真にならないためです。
残したいなら、条件は `ON` に書きます。 ON は「どれとどれをつなぐか」の条件、WHERE は「つないだ結果から何を残すか」の条件です。評価される順番が違います。
見分け方: 外部結合で右の表の条件を `WHERE` に書いたら、それは内部結合と同じになっていないか疑ってください。
SELECT s.name, b.busho_name
FROM shain s
LEFT JOIN busho b ON b.busho_id = s.busho_id
WHERE b.busho_name <> '経営'
ORDER BY s.shain_id;| name | busho_name |
|---|---|
| 佐藤 | 開発 |
| 田中 | 開発 |
| 中村 | 開発 |
| 小林 | 開発 |
| 加藤 | 基盤 |
(15 行 … うち先頭 5 行を表示)
「経営以外」を出したかっただけなのに、部署が決まっていない社員まで消えています。
SELECT s.name, b.busho_name
FROM shain s
LEFT JOIN busho b ON b.busho_id = s.busho_id AND b.busho_name <> '経営'
ORDER BY s.shain_id;| name | busho_name |
|---|---|
| 鈴木 | NULL |
| 佐藤 | 開発 |
| 田中 | 開発 |
| 中村 | 開発 |
| 小林 | 開発 |
(18 行 … うち先頭 5 行を表示)
条件に合わない部署は「つながなかった」ことになり、部署名が NULL になります。社員は 1 人も減りません。
05⚠️ よくある間違い:件数を数えるときは count(*) を使わない
外部結合したあとに count(*) で数えると、相手がいない行も 1 と数えてしまいます。
count(*) は「行の数」を数えるので、右の列が全部 NULL の行も 1 行として数に入ります。「社員が 0 人の部署」が 1 人と表示される、という形で表面化します。
`count(列名)` を使ってください。 こちらは NULL を数えません。
SELECT b.busho_name, count(*) AS machigai, count(s.shain_id) AS tadashii
FROM busho b
LEFT JOIN shain s ON s.busho_id = b.busho_id
GROUP BY b.busho_id, b.busho_name
ORDER BY b.busho_id;| busho_name | machigai | tadashii |
|---|---|---|
| 経営 | 1 | 1 |
| 開発 | 4 | 4 |
| 営業 | 4 | 4 |
| 管理 | 3 | 3 |
| 基盤 | 2 | 2 |
| 法務 | 1 | 0 |
| マーケ | 2 | 2 |
(7 行)
社員が 0 人の部署で、左は 1、右は 0 になっています。正しいのは右です。
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
- INNER JOIN相手がいない行を消してよいなら、内部結合のほうが素直です。
- FULL OUTER JOIN左右どちらの行も残したいときに使います。
- ON 句と USING 句ON と WHERE の違いは、外部結合でいちばん効いてきます。
- IS NULL「相手がいなかった行」を取り出すのに使います。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 問い合わせ — 結合テーブル一次情報・確認 2026-07-28
- Oracle Database SQL Language Reference: SELECT(outer join)一次情報・確認 2026-07-28
- SQLite: SELECT(join-clause)一次情報・確認 2026-07-28