外部結合は、2テーブルの指定カラムでデータを結合しデータを取得します。一致しないデータについては、NULLとしてデータを取得します。
外部結合には、LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOINの3種類があります。
外部結合のサンプルコード
実際にコピペして動作を確認できる、SQLの外部結合のサンプルコードを紹介します。
以下、データベースとして、MySQLのサンプルデータベースEmployeesを使っています。SQL実行結果の表示にはphpMyAdminを使用しています。
3テーブルの外部結合サンプル
employees(社員)テーブルに、下記の1レコードを挿入します。
emp_no=500000の場合、対応するdept_name(部署名)データが存在しない状態です。
外部結合でデータを抽出してみましょう。想定では、dept_nameがNULLとして取得されるはずです。
SELECT first_name, last_name, dept_name FROM employees left outer join dept_emp on employees.emp_no = dept_emp.emp_no left outer join departments on departments.dept_no = dept_emp.dept_no where employees.emp_no = 500000
SQLの実行結果は以下の通りです。
予想通り、Taro Yamadaのdept_nameがNULLとして取得できました。
right join を left joinに置き換えるサンプル
right joinは、left joinに置き換え可能です。
下記は、departments(部署名)テーブルとdept_emp(部署名・社員紐付け用テーブル)をright joinするSQLです。
select * from departments right join dept_emp on dept_emp.dept_no = departments.dept_no
実行結果は、以下の通り。
上記SQLをleft joinに置き換えるには、単純にテーブル名を入れ替えます。
具体的には、以下のようにSQLを書き換えます。
select * from dept_emp left join departments on dept_emp.dept_no = departments.dept_no
実行結果はこうなります。
select *で抽出すると、カラムの並び順が異なる点に注意が必要です。
開発案件では、混乱を避けるため、left joinのみに統一することもあります。
完全外部結合
2テーブルを互いに全件外部結合する方法です。FULL Outer Joinと呼ばれることもあります。
データベースによっては実装されていません。(例えば、MySQLなどは未実装)
完全外部結合の使いどころは、実際の開発案件ではほとんどないでしょう。
なお、完全外部結合は、left outer joinとright outer joinにunionを組み合わせることで同じ結果を得ることが可能です。
参考)【MySQL5.6】完全外部結合(FULL OUTER JOIN)のやりかた – Qiita
外部結合が効かないケース 絞り込み条件は、where句に記述する
SELECT first_name, last_name, dept_name FROM employees left outer join dept_emp on employees.emp_no = dept_emp.emp_no and employees.emp_no = 500000 left outer join departments on departments.dept_no = dept_emp.dept_no
上記SQLを実行すると、このような結果になります。
全てのdept_name(部署名)がNULLとなって取得されてしまいました。
どういう理由で、この結果になったのでしょうか?
一言で言うと「絞り込み条件は、where句に指定する」ということになります。
処理の流れをまとめると以下のようになります。
- left outer joinでは、left側のテーブル(employees)を全件抽出する。
- onで指定した条件で抽出できなかったカラムはNULLを抽出する。
- 「Taro Yamada」以外のデータは、全てdept_nameとしてNULLを取得する。
- employees.emp_no = 500000 という条件で、「Taro Yamada」のデータのみdept_nameが抽出できるはずが、dept_empにデータが存在しないため、結局dept_nameとしてNULLを取得する。
外部結合のleft、rightのイメージ
外部結合(outer join)には、left outer join、right outer joinの指定があります。
上記のベン図をイメージしておくと良いでしょう。
詳細は下記を参照してください。
【関連記事】
SQL Joinサンプル集 Joinで遅いSQLの原因を調べる方法
内部結合と外部結合のパフォーマンスの差は
実務の場では、マスターテーブルなどデータが保証されている場合は内部結合で良い所を外部結合を使うケースがあります。
万が一のデータの不整合があった場合に、データが欠落するよりはNULL値でも取得したほうが良いという場合です。
しかし、パフォーマンスはどうなるのでしょうか?
「outer joinは効率が悪い」という声もあります。
employeesテーブル(30万件)と、salariesテーブル(280万件)を結合して試してみました。
left joinの実行時間は以下の通り。
select * from employees left join salaries on salaries.emp_no=employees.emp_no
Showing rows 0 – 24 (2844048 total, Query took 0.0004 seconds.)
inner joinの実行時間は以下の通り。
select * from employees inner join salaries on salaries.emp_no=employees.emp_no
Showing rows 0 – 24 (2844048 total, Query took 0.0004 seconds.)
一見、どちらでもパフォーマンスは変わらないように見えます。念のため、explainで実行計画を確認してみましょう。
内部結合(inner join)ではemployeesテーブル検索に主キー(PRIMARY)を使用可能なのに対し、外部結合(left outer join)では、検索にキーを使用できません。
単純なケースでは差が出なくても、SQLが複雑化すると外部結合の方が遅くなる可能性があります。
外部結合のまとめ
- 外部結合でデータの絞り込みをおこなう場合はwhere句に指定を記述する。
- 外部結合のleft、right指定にはベン図をイメージする
- 完全外部結合は、left outer join、right outer join、unionを組み合わせて実現できる
- 内部結合より、外部結合がパフォーマンスが悪くなるケースがある。
left outer joinは、onにどんな条件を指定しても、left側のテーブルを全件抽出する。