コマンド道場

FULL OUTER JOIN の使い方

ひとことで言うと

shain社員

namebusho_id
中村2
大野NULL

busho部署

busho_idbusho_name
2開発
6法務

FULL JOINつないだ結果

namebusho_idbusho_name
中村2開発
大野NULLNULL
NULLNULL法務
  • 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 JOINFULL OUTER JOIN は同じ意味です。

1 行ずつ、何をしているか
  1. SELECT s.name, b.busho_name何を出すか
  2. FROM shain s左(残す)
  3. FULL JOIN busho b右(こちらも残す)
  4. ON b.busho_id = s.busho_idどの列どうしが同じか
  5. 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;
namebusho_name
鈴木経営
佐藤開発
田中開発
中村開発
小林開発
山田営業
高橋営業
伊藤営業

19 … うち先頭 8 行を表示

末尾に「部署が NULL の社員」が、途中に「社員が NULL の部署」が現れます。

⚠️ この書き方は MySQL / MariaDB / SQL Server では使えません(FULL OUTER JOIN・ORDER BY ... NULLS LAST)。製品ごとの対応表

02どちら側が欠けたのかは結合キーで見分ける

結果の NULL を見ただけでは、「もともと NULL だった」のか「相手がいなかった」のかが分かりません。

見分けるには結合に使った列そのものを見ます。b.busho_idNULL なら右に相手がいなかった行、s.shain_idNULL なら左に相手がいなかった行です。

この判定を 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;
namebusho_namejotai
鈴木経営両方あり
佐藤開発両方あり
田中開発両方あり
中村開発両方あり
小林開発両方あり
加藤基盤両方あり

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;
namebusho_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)でも当然動きます。移植する予定があるなら、最初からこちらで書いておくのも手です。

FULL を使わずに同じ結果を得る
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;
namebusho_name
井上マーケ
木村マーケ
伊藤営業
山田営業
松本営業
高橋営業

19 … うち先頭 6 行を表示

UNION は重複を取り除くので、両方に現れる行が二重になりません。

⚠️ この書き方は MySQL / MariaDB / SQL Server では使えません(ORDER BY ... NULLS LAST)。製品ごとの対応表

自分で打ってみる

このページの例と同じデータが入った本物のデータベースを、この場(あなたのブラウザの中)で起動できます。打った SQL がサーバーへ送られることはありません。

押すと初回だけ約 9MB を読み込みます(2 回目以降はキャッシュされます)。

解いてみる

読んだだけでは書けるようになりません。実行結果で採点します。

関連するトピック

根拠(一次情報)