コマンド道場

LEFT / RIGHT OUTER JOIN の使い方

ひとことで言うと

shain社員

namebusho_id
中村2
大野NULL

busho部署

busho_idbusho_name
2開発
6法務

LEFT JOINつないだ結果

namebusho_idbusho_name
中村2開発
大野NULLNULL
  • 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 JOINLEFT OUTER JOIN はまったく同じ意味です。

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

16 … うち先頭 5 行を表示

② 外部結合(全員残り、部署が NULL になる)
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;
namebusho_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;
namebusho_idbusho_name
渡辺NULLNULL
大野NULLNULL

2

結合してから「相手がいなかった行」だけを残す書き方です。

03向きを変えると、残る側が変わる

RIGHT OUTER JOIN は右の表を必ず残します。左右が入れ替わるだけで、考え方は同じです。

実務では `LEFT` に統一するのが一般的です。FROM に書いた表が主役、という読み方が崩れないからです。RIGHT を使いたくなったら、表の順番を入れ替えて LEFT にできないか考えてみてください。

次の例では、社員が 1 人もいない部署を出しています。部署を必ず残したいので、部署を左に置いて LEFT で書いています。

社員が 1 人もいない部署
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_namename
法務NULL

1

04⚠️ よくある間違い:WHERE に条件を書くと、外側の行が消える

これが外部結合でいちばん多い事故です。

せっかく LEFT JOIN で残した行が、`WHERE` に右の表の条件を書いた瞬間に消えます。相手がいない行では右の列が NULL になり、NULL を使った比較は真にならないためです。

残したいなら、条件は `ON` に書きます。 ON は「どれとどれをつなぐか」の条件、WHERE は「つないだ結果から何を残すか」の条件です。評価される順番が違います。

見分け方: 外部結合で右の表の条件を `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;
namebusho_name
佐藤開発
田中開発
中村開発
小林開発
加藤基盤

15 … うち先頭 5 行を表示

「経営以外」を出したかっただけなのに、部署が決まっていない社員まで消えています。

ON に書いた場合(社員は全員残る)
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;
namebusho_name
鈴木NULL
佐藤開発
田中開発
中村開発
小林開発

18 … うち先頭 5 行を表示

条件に合わない部署は「つながなかった」ことになり、部署名が NULL になります。社員は 1 人も減りません。

05⚠️ よくある間違い:件数を数えるときは count(*) を使わない

外部結合したあとに count(*) で数えると、相手がいない行も 1 と数えてしまいます

count(*) は「行の数」を数えるので、右の列が全部 NULL の行も 1 行として数に入ります。「社員が 0 人の部署」が 1 人と表示される、という形で表面化します。

`count(列名)` を使ってください。 こちらは NULL を数えません。

count(*) と count(列) を並べて比べる
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_namemachigaitadashii
経営11
開発44
営業44
管理33
基盤22
法務10
マーケ22

7

社員が 0 人の部署で、左は 1、右は 0 になっています。正しいのは右です。

自分で打ってみる

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

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

解いてみる

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

関連するトピック

  • INNER JOIN相手がいない行を消してよいなら、内部結合のほうが素直です。
  • FULL OUTER JOIN左右どちらの行も残したいときに使います。
  • ON 句と USING 句ON と WHERE の違いは、外部結合でいちばん効いてきます。
  • IS NULL「相手がいなかった行」を取り出すのに使います。

根拠(一次情報)