内部結合と外部結合の違い:残る行・NULL・左外部結合と右外部結合・SQLの書き方を比較

結合(JOIN)は、2つの表の行を、ONで指定した条件(多くは外部キーと主キーの値が等しいこと)で組み合わせて、1つの結果の表を作る操作です。内部結合は、条件に一致する相手がある行の組み合わせだけを結果に残し、相手がない行は、どちらの表のものも消えます。外部結合は、一致する組み合わせに加えて、指定した側の表の行を、相手がなくても残し、相手の表の列をNULLで埋めます。左側の表の行をすべて残すのが左外部結合(LEFT OUTER JOIN)、右側を残すのが右外部結合(RIGHT OUTER JOIN)、両方を残すのが完全外部結合(FULL OUTER JOIN)です。「相手がない行も結果に出したいか」で使い分けます。

項目内部結合(INNER JOIN)外部結合(OUTER JOIN)
結果に残る行結合の条件に一致する行の組み合わせだけ一致する組み合わせに加えて、残す側に指定した表の、一致する相手がない行
相手がない行の扱い左右どちらの表の行も、結果から消える残す側の行は、相手の表の列をNULLにして1行として残る。残す側でない表の行は消える
種類1種類。INNERを省いて JOIN とだけ書いてもよい左外部結合(LEFT)、右外部結合(RIGHT)、完全外部結合(FULL)の3種類。OUTERは省いてもよい
SQLの書き方の例SELECT … FROM 社員 INNER JOIN 部署 ON 社員.部署ID = 部署.部署IDSELECT … FROM 社員 LEFT OUTER JOIN 部署 ON 社員.部署ID = 部署.部署ID
結果の行数の例(社員4人のうち1人は部署IDがNULL、3つの部署のうち1つは社員がいない)3行。部署IDがNULLの社員と、社員のいない部署は出てこない社員表を残す左外部結合では4行(部署IDがNULLの社員は部署名がNULLになる)。両方を残す完全外部結合では5行
表を書く順番左右を入れ替えても、結果の行は同じ(列の並びは変わる)左外部結合と右外部結合では、どちらの表を左に書くかで結果が変わる。A LEFT OUTER JOIN B と B RIGHT OUTER JOIN A は同じ行を返す
相手の表の列への条件ONに書いても、WHERE句に書いても、結果は同じWHERE句に書くと、NULLで埋めた行が条件を満たさずに消え、内部結合と同じ結果になることがある。相手がない行も残したいときはONに書く
主な用途両方の表にデータがそろっているものだけを使いたいとき(注文に顧客の氏名を付けるなど)相手がない行も含めて一覧にしたいとき(部署が未設定の社員も含めた社員の一覧など)、相手がない行を探したいとき

数値は代表的な目安で、世代や製品によって異なります。

どんなときに使うか

内部結合
両方の表に対応するデータがある行だけが必要なときに使います。例えば、注文の一覧に顧客の氏名を付けるとき、顧客が分からない注文は不要なら内部結合です。
外部結合
相手がない行も落とさずに出したいときに使います。例えば、全社員の一覧に部署名を付け、部署が未設定の社員も残したいときは、社員表を残す左外部結合です。外部結合をして、相手の表の主キーの列がNULLの行を選べば、一度も注文していない顧客のように、相手がない行を見つけることもできます。

よくある質問

左外部結合と右外部結合は、どう違いますか?

どちらの表の行をすべて残すかだけが違います。左外部結合はFROMに先に書いた左側の表の行を、右外部結合は後に書いた右側の表の行を、相手がなくても残します。A LEFT OUTER JOIN B と B RIGHT OUTER JOIN A は同じ行を返すので、読みやすさのために左外部結合にそろえて書くことも多いです。

結合の結果が、もとの表より多くの行になるのはなぜですか?

結合では、条件を満たす行の組み合わせが1つずつ結果の行になるからです。結合する列の値が両方の表で重複していると、組み合わせの数が掛け算で増えます。例えば、値が1の行が片方に2行、もう片方に2行あれば、その値だけで 2 × 2 = 4 行になります。

結合の条件を付けないと、どうなりますか?

2つの表のすべての行の組み合わせ(直積)になります。これをCROSS JOINと呼び、4行の表と3行の表なら 4 × 3 = 12 行です。ONの書き忘れなどで意図せずに直積を作ると、結果の行数が急に増えるので注意が必要です。

NULLどうしは、結合の条件で一致しますか?

一致しません。SQLでは、NULLとの比較は真にならないので、両方の表の結合する列がNULLの行どうしも組み合わさりません。そのため、内部結合では、結合する列がNULLの行は結果から消えます。

理解度チェック

社員表(社員番号, 氏名, 部署ID)に4行あり、部署IDは順に10、20、10、NULLである。部署表(部署ID, 部署名)には部署IDが10、20、30の3行がある。SELECT 社員.氏名, 部署.部署名 FROM 社員 INNER JOIN 部署 ON 社員.部署ID = 部署.部署ID の結果は何行になるか。

  1. A3行
  2. B4行
  3. C12行
答えと解説を見る

正解:A. 3行

INNER JOIN(内部結合)は、ON の条件を満たす行の組み合わせだけを結果にします。部署IDが10の社員2人は部署10の行と、部署IDが20の社員1人は部署20の行と組み合わさるので、結果は3行です。部署IDがNULLの社員は、NULLとの比較が真にならないので、どの部署とも結合されずに結果から消えます。また、社員のいない部署30も結果に出てきません。4行は、社員表のすべての行を残す左外部結合(社員 LEFT OUTER JOIN 部署)の場合の行数です。12行は、条件を付けずにすべての組み合わせを作るCROSS JOIN(直積)の 4 × 3 = 12 行です。

社員表(社員番号, 氏名, 部署ID)に5行あり、部署IDは順に10、20、10、NULL、NULLである。部署表(部署ID, 部署名)には部署IDが10、20、30の3行がある。SELECT 部署.部署名, 社員.氏名 FROM 部署 LEFT OUTER JOIN 社員 ON 部署.部署ID = 社員.部署ID の結果は何行になるか。

  1. A3行
  2. B4行
  3. C5行
答えと解説を見る

正解:B. 4行

LEFT OUTER JOIN(左外部結合)は、左側の表(ここでは部署表)のすべての行を残し、右側の表に一致する行がなければ、右側の列をNULLで埋めて1行にします。部署10には社員が2人いるので2行、部署20は1行、社員のいない部署30は氏名がNULLの1行になり、合計4行です。部署IDがNULLの社員2人は、どの部署とも一致せず、残す対象ではない右側の表の行なので、結果には出てきません。内部結合なら部署30の行も消えて3行です。表の左右を逆にして 社員 LEFT OUTER JOIN 部署 とすると、社員5人がすべて残るので5行になります。外部結合では、どちらの表の行をすべて残すのかを確かめることが大切です。

表Rの列xの値は 1、1、2、3 の4行、表Sの列xの値は 1、1、2、4 の4行である。SELECT * FROM R INNER JOIN S ON R.x = S.x の結果は何行になるか。

  1. A2行
  2. B3行
  3. C5行
答えと解説を見る

正解:C. 5行

結合では、条件を満たす行の組み合わせが1つずつ結果の行になります。x = 1 については、Rの2行とSの2行のすべての組み合わせが条件を満たすので 2 × 2 = 4 行、x = 2 については 1 × 1 = 1 行です。Rの3とSの4は相手がいないので、内部結合の結果には出てきません。合計は 4 + 1 = 5 行です。2行は、一致する値の種類(1と2)ごとに1行ずつしかできないと考えた場合の行数です。3行は、Rの各行についてSに一致する値があるかどうかだけを見た場合(SELECT * FROM R WHERE x IN (SELECT x FROM S) のような問い合わせ)の行数です。条件を付けない直積なら 4 × 4 = 16 行になります。結合する列の値が重複していると、結果の行が掛け算で増えることに注意が必要です。

  1. 顧客表(顧客ID, 氏名)と注文表(注文ID, 顧客ID, 金額)から、一度も注文していない顧客の氏名を求めたい。正しいSQL文はどれか。

データベースの基礎の練習問題へ

関連する用語の解説

SQL
関係データベースで、表の定義、データの検索・追加・更新・削除、権限の制御などを行うための標準の言語。ISO/IECとJISで規格化されている。SELECT、INSERT、UPDATE、DELETE、CREATE TABLE、GRANTなどの文がある。
関係データベース
データを行と列からなる表(関係、リレーション)で表し、表どうしを共通の値で関連付けて扱うデータベース。リレーショナルデータベース(RDB)とも呼ぶ。SQLで問い合わせや更新を行い、主キーや外部キーなどの制約でデータの整合性を保つ。
主キー
表の中の1行を一意に識別するための列、または列の組。値が重複せず、NULLを含まないという制約を持つ。行を一意に識別できる最小限の列の組(候補キー)の中から1つを選んで主キーにする。
外部キー
ほかの表の主キー(または一意な列)を参照する列。参照先に存在する値かNULLしか入れられないという参照整合性制約により、存在しない行を指すデータが入るのを防ぐ。参照先の行を削除・更新したときの動作(拒否、連鎖して削除など)も指定できる。
正規化
関係データベースの表を、列どうしの関数従属に基づいて分割し、同じ事実が何か所にも記録されないようにする設計の手順。データの重複をなくし、更新時異常・挿入時異常・削除時異常を防ぐ。第1正規形から第3正規形、ボイス・コッド正規形などの段階がある。
ビュー
関係データベースで、SELECT文に名前を付けて定義する仮想的な表。ふつうは自分ではデータを持たず、参照するたびに元の表から結果を作る。複雑な問い合わせを簡単にしたり、見せる列や行を絞ってアクセスできる範囲を制限したりするのに使う。

関連する比較