FULL OUTER JOIN の使い方
shain社員
| name | busho_id |
|---|---|
| 中村 | 2 |
| 大野 | NULL |
| … | |
busho部署
| busho_id | busho_name |
|---|---|
| 2 | 開発 |
| 6 | 法務 |
| … | |
FULL JOINつないだ結果
| name | busho_id | busho_name |
|---|---|---|
| 中村 | 2 | 開発 |
| 大野 | NULL | NULL |
| NULL | NULL | 法務 |
| … | ||
- busho_nameのように、右の表の列が左の表にくっつくのが結合です。
- 社員 18 行 → つないだ結果 19 行(1 行増えました)
- 結果に
NULLが入っている行は、相手がいないまま残った行です。
社員側の「部署が決まっていない人」も、部署側の「社員が 0 人の部署」も、どちらも残ります。
FULL OUTER JOIN は「左右どちらの行も 1 行も捨てない」結合です。 相手が見つからなかった行は、相手側の列を NULL にして残します。2 つの表を突き合わせて「どちらか片方にしか無いもの」を洗い出すのが主な用途です。
この書き方が使えない製品があります そのまま使える: PostgreSQL / SQLite / SQL Server / Oracle Database / IBM Db2
- MySQL では使えません(FULL OUTER JOIN)
- MariaDB では使えません(FULL OUTER JOIN)
このページの実行結果と図は、すべて本物のデータベースに同じ SQL を流して得たものです。手で書いた「たぶんこうなる」ではありません。
013 種類の行が混ざった結果になる
結論: `FULL OUTER JOIN` の結果には 3 種類の行が混ざります。
- 両方に相手がいた行(どちらの列も値が入る)
- 左にしかない行(右側の列が
NULL) - 右にしかない行(左側の列が
NULL)
内部結合は 1 種類目だけ、LEFT JOIN は 1・2 種類目だけを返します。全部返すのが FULL です。
OUTER は省略できます。FULL JOIN と FULL OUTER JOIN は同じ意味です。
SELECT s.name, b.busho_name何を出すかFROM shain s左(残す)FULL JOIN busho b右(こちらも残す)ON b.busho_id = s.busho_idどの列どうしが同じかORDER BY b.busho_id, s.shain_id並び順
SELECT s.name, b.busho_name
FROM shain s
FULL JOIN busho b ON b.busho_id = s.busho_id
ORDER BY b.busho_id NULLS LAST, s.shain_id;| name | busho_name |
|---|---|
| 鈴木 | 経営 |
| 佐藤 | 開発 |
| 田中 | 開発 |
| 中村 | 開発 |
| 小林 | 開発 |
| 山田 | 営業 |
| 高橋 | 営業 |
| 伊藤 | 営業 |
(19 行 … うち先頭 8 行を表示)
末尾に「部署が NULL の社員」が、途中に「社員が NULL の部署」が現れます。
⚠️ この書き方は MySQL / MariaDB / SQL Server では使えません(FULL OUTER JOIN・ORDER BY ... NULLS LAST)。製品ごとの対応表
02どちら側が欠けたのかは結合キーで見分ける
結果の NULL を見ただけでは、「もともと NULL だった」のか「相手がいなかった」のかが分かりません。
見分けるには結合に使った列そのものを見ます。b.busho_id が NULL なら右に相手がいなかった行、s.shain_id が NULL なら左に相手がいなかった行です。
この判定を CASE 式に入れると、行ごとに「どちら側の問題か」をラベル付けできます。突き合わせの結果を人に見せるときに便利です。
SELECT
s.name,
b.busho_name,
CASE
WHEN s.shain_id IS NULL THEN '社員がいない部署'
WHEN b.busho_id IS NULL THEN '部署が決まっていない社員'
ELSE '両方あり'
END AS jotai
FROM shain s
FULL JOIN busho b ON b.busho_id = s.busho_id
ORDER BY jotai, s.shain_id NULLS LAST;| name | busho_name | jotai |
|---|---|---|
| 鈴木 | 経営 | 両方あり |
| 佐藤 | 開発 | 両方あり |
| 田中 | 開発 | 両方あり |
| 中村 | 開発 | 両方あり |
| 小林 | 開発 | 両方あり |
| 加藤 | 基盤 | 両方あり |
(19 行 … うち先頭 6 行を表示)
⚠️ この書き方は MySQL / MariaDB / SQL Server では使えません(FULL OUTER JOIN・ORDER BY ... NULLS LAST)。製品ごとの対応表
03本来の使いどころは「突き合わせ」
FULL OUTER JOIN がいちばん効くのは、2 つの表を突き合わせて食い違いを洗い出す場面です。
「マスタにあるのに実績が無い」「実績にあるのにマスタに無い」を一度の問い合わせで両方出せます。片方向の LEFT JOIN を 2 回書いて UNION するより短く、漏れも起きません。
食い違いだけが欲しいなら、両側のキーのどちらかが `NULL` の行に絞ります。
SELECT s.name, b.busho_name
FROM shain s
FULL JOIN busho b ON b.busho_id = s.busho_id
WHERE s.shain_id IS NULL OR b.busho_id IS NULL
ORDER BY b.busho_id NULLS LAST;| name | busho_name |
|---|---|
| NULL | 法務 |
| 渡辺 | NULL |
| 大野 | NULL |
(3 行)
「社員が 0 人の部署」と「部署が決まっていない社員」だけが残ります。棚卸しのときにそのまま使える形です。
⚠️ この書き方は MySQL / MariaDB / SQL Server では使えません(FULL OUTER JOIN・ORDER BY ... NULLS LAST)。製品ごとの対応表
04⚠️ よくある間違い:使えない製品がある
FULL OUTER JOIN は対応していない製品があります。実測したところ、MySQL・MariaDB・SQLite では通りませんでした。
代わりの書き方は「LEFT JOIN の結果と RIGHT JOIN の結果を UNION する」です。少し長くなりますが、どの製品でも動きます。
下の例は本サイトの実行環境(PostgreSQL)でも当然動きます。移植する予定があるなら、最初からこちらで書いておくのも手です。
SELECT s.name, b.busho_name
FROM shain s
LEFT JOIN busho b ON b.busho_id = s.busho_id
UNION
SELECT s.name, b.busho_name
FROM shain s
RIGHT JOIN busho b ON b.busho_id = s.busho_id
ORDER BY 2 NULLS LAST, 1;| name | busho_name |
|---|---|
| 井上 | マーケ |
| 木村 | マーケ |
| 伊藤 | 営業 |
| 山田 | 営業 |
| 松本 | 営業 |
| 高橋 | 営業 |
(19 行 … うち先頭 6 行を表示)
UNION は重複を取り除くので、両方に現れる行が二重になりません。
⚠️ この書き方は MySQL / MariaDB / SQL Server では使えません(ORDER BY ... NULLS LAST)。製品ごとの対応表
自分で打ってみる
このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。
押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。
解いてみる
読んだだけでは書けるようになりません。実行結果で採点します。
関連するトピック
- LEFT / RIGHT OUTER JOIN片側だけ残したいなら LEFT / RIGHT で足ります。
- INNER JOIN両方に相手がいる行だけでよいなら内部結合です。
- UNION / UNION ALL(練習問題)FULL が使えない製品での代替に使います。
- IS NULL「どちら側が欠けたか」の判定に使います。
根拠(一次情報)
- PostgreSQL 18 マニュアル: 問い合わせ — 結合テーブル一次情報・確認 2026-07-28
- SQLite: SELECT(join-clause)一次情報・確認 2026-07-28
- Oracle Database SQL Language Reference: SELECT(outer join)一次情報・確認 2026-07-28