SQLでSELECT文を書いていると、複数のテーブルをがっちゃんこしたい!と思う時があるでしょう。これをSQLではテーブル結合と言います。
テーブル結合ができるようになれば、分析の幅が大きく広がります。むしろ、テーブル結合なしには分析ができないと言っても過言ではないくらい重要です。
本記事ではテーブル結合とは何か?から始まり、結合の種類や使い方について詳しく解説しています。
目次
SQLのテーブル結合とは
SQLのテーブル結合とは、文字通り複数のテーブルを結合することを指します。
これだけではイメージが付きにくいので図解を交えて解説します。
例えば、ユーザー情報を管理するusersテーブルと、注文情報を管理するorderテーブルが存在したとします。
ここからユーザーが注文した商品を集計したい時どうすればいいでしょう。
1つ考えられるやり方として、usersテーブルとorderテーブルの情報をそれぞれ抽出して、エクセルにインポートして照合する方法です。
しかし、毎回これをするのは面倒ですし何よりも時間がかかります。
できることならSQL上で統合を行なって分析を行いたいものです。これを実現するのが「SQLのテーブル結合」です。
テーブル結合を使えばエクセルで行っていた統合作業をSQL上で行うことができます。
usersテーブルのID
とorderテーブルのuser_id
は一致するため、この2つを起点としてテーブルを結合することができます。
今回はid
情報を元に結合を行いましたが、複数のテーブルで同じ値を扱うカラムが存在すればid
以外でもテーブル結合は可能です。
例えば、テーブルAとテーブルBのどちらにもemail
の情報が存在していれば、email
を起点としてテーブル結合をするといった具合です。
SQLで使える結合は5種類
テーブル結合とは何かを説明してきましたが、実は結合の種類は一つではありません。
下記の5種類が存在します。
結合の種類 | イメージ図 | 概要 |
---|---|---|
1. 内部結合 (INNER JOIN) | 値が一致したレコードだけを結合 | |
2. 外部結合 (LEFT OUTER JOIN) | 左(A)の全てのレコードを取得 + 左(A)と値が一致した右(B)のレコードを結合 | |
3. 外部結合 (RIGHT OUTER JOIN) | 右(B)の全てのレコードを取得 + 右(B)と一致した左(A)のレコードを結合 | |
4. 外部結合 (FULL OUTER JOIN) | 左(A)と右(B)の全てのレコードを取得 | |
5. クロス結合 (CROSS JOIN) | テーブルの全ての組み合わせを取得 |
それでは、具体例を交えて一つずつ解説していきます。
サンプルデータ
下記のとおり、employeeテーブルとdepartmentテーブルを用意します。
employeeテーブルは従業員情報を管理し、departmentテーブルは配属部門を管理しています。
employeeテーブル
id | name | department_id |
---|---|---|
1 | 山田 | 3 |
2 | 鈴木 | 4 |
3 | 佐藤 | 1 |
4 | 佐々木 | 6 |
5 | 丸山 | 1 |
departmentテーブル
id | name |
---|---|
1 | 営業部 |
2 | 人事部 |
3 | 企画部 |
4 | 経理部 |
5 | 開発部 |
SQLの内部結合「INNER JOIN」
内部結合は、それぞれのテーブルで指定した値が一致したレコードだけを結合します。実務で最も使うのがINNER JOIN
を使った内部結合なので、必ず押さえておきましょう。
INNER(内部)というだけあって、
テーブルAとテーブルBの一致したレコードのみを取得
今回の場合、employeeテーブルのdepartment_id
とdepartmentテーブルのid
が同じ意味を持つカラムになっているため、この2つを起点として結合を行います。
結果、department_id
とid
カラムそれぞれの値が一致したレコードだけが結合されます。これが内部結合INNER JOIN
です。
INNER JOIN
の基本構文が下記です。
SELECT カラム名
FROM テーブル名1
INNER JOIN テーブル名2
ON 結合の条件;
INNER JOIN
の後に結合するテーブル名を記載し、ON
の後にテーブル名1
とテーブル名2
を結合するための条件を記載します。
検索クエリ
employeeテーブルとdepartmentテーブルを内部結合して取得する
SELECT *
FROM employee
INNER JOIN department
ON employee.department_id = department.id;
考え方は下記です。
- SELECT文でemployeeテーブルから全ての情報を取得する命令を出す
INNER JOIN
でdepartmentテーブルをemployeeテーブルに結合する命令を出すON
の後にemployee.department_id = department.id
と書くことで、employeeテーブルとdepartmentテーブルを結合するための条件を指定
実行結果
id | name | department_id | id | name |
---|---|---|---|---|
3 | 佐藤 | 1 | 1 | 営業部 |
1 | 山田 | 3 | 3 | 企画部 |
2 | 鈴木 | 4 | 4 | 経理部 |
5 | 丸山 | 1 | 1 | 営業部 |
department_id
とid
が結合された上でレコードを取得することができました。両方のカラムに存在する値だけが残っていることが分かります。
また、テーブルを結合すると同じ名前のカラムが複数できるので、AS句を使って別名をつけると分かりやすくなります。
内部結合INNER JOINについては下記でも詳しくまとめています。
【SQL】INNER JOINを使ってテーブルを結合する方法SQLの外部結合「OUTER JOIN」
外部結合は、内部結合のように2つのテーブルで指定したカラムの値が一致するレコードに加えて、どちらかのテーブルにしか存在しないレコードも取得します。
そして、外部結合には下記の3種類が存在します。
- LEFT OUTER JOIN
- RIGHT OUTER JOIN
- FULL OUTER JOIN
それぞれ順に見ていきましょう。
LEFT OUTER JOIN
左側のテーブル全て
+
テーブルAとテーブルBの一致したレコード
今回の場合、テーブルAをemployeeテーブルとすると、department_id
が結合の起点になります。
下記の図のようにdepartment_id
のレコードは全て取得した上で、テーブルBのdepartmentテーブルのid
が一致するレコードを取得します。
そしてポイントが、結合先であるdepartmentテーブルに存在しない値がある場合にはNULL
が割り当てられるということです。department_idが6
に一致する値はdepartmentテーブルには存在しないためNULL
となっています。
あくまで左側のテーブルが起点となるのが左外部結合のLEFT OUTER JOIN
です。
LEFT OUTER JOIN
の基本構文が下記です。
SELECT カラム名
FROM テーブル名1
LEFT OUTER JOIN テーブル名2
ON 結合の条件;
テーブル名1に結合元(起点)となるテーブルを指定し、テーブル名2に結合先のテーブルを指定します。
検索クエリ
employeeテーブルにdepartmentテーブルを左外部結合(LEFT OUTER JOIN)して取得する
SELECT *
FROM employee
LEFT OUTER JOIN department
ON employee.department_id = department.id;
考え方は下記です。
- SELECT文でemployeeテーブルから全ての情報を取得する命令を出す
LEFT OUTER JOIN
でemployeeテーブルを起点として、departmentテーブルを結合する命令を出すON
の後にemployee.department_id = department.id
と書くことで、employeeテーブルとdepartmentテーブルを結合するための条件を指定
また、LEFT OUTER JOIN
はLEFT JOIN
と省略して書くことも可能です。
実行結果
id | name | department_id | id | name |
---|---|---|---|---|
3 | 佐藤 | 1 | 1 | 営業部 |
1 | 山田 | 3 | 3 | 企画部 |
2 | 鈴木 | 4 | 4 | 経理部 |
4 | 佐々木 | 6 | NULL | NULL |
5 | 丸山 | 1 | 1 | 営業部 |
employeeテーブルを起点としてdepartmentテーブルを結合することができました。departmentテーブルはid
が6
の値は存在しないため、代わりにNULLが割り当てられています。
LEFT OUTER JOINについては下記の記事でも詳しくまとめています。
【SQL】LEFT OUTER JOINを使って外部結合をする方法RIGHT OUTER JOIN
右側のテーブル全て
+
テーブルAとテーブルBの一致したレコード
RIGHT OUTER JOIN
はLEFT OUTER JOIN
の真逆と覚えておけばOKです。右側のテーブルに対して左側のテーブルを結合します。今回の場合は、departmentテーブルに対してemployeeテーブルを結合することになります。
下記の図のようにdepartmentテーブルのid
は全て取得した上で、employeeテーブルのdepartment_id
が一致するレコードを取得します。
結合元のdepartmentテーブルのid
に存在して、結合先であるemployeeテーブルのdepartment_id
に存在しない値があれば、NULL
が割り当てられます。
あくまで右側のテーブルが起点となるのが右外部結合のRIGHT OUTER JOIN
です。
RIGHT OUTER JOIN
の基本構文が下記です。
SELECT カラム名
FROM テーブル名1
RIGHT OUTER JOIN テーブル名2
ON 結合の条件;
検索クエリ
employeeテーブルにdepartmentテーブルを右外部結合(RIGHT OUTER JOIN)して取得する
SELECT *
FROM employee
RIGHT OUTER JOIN department
ON employee.department_id = department.id;
また、RIGHT OUTER JOIN
はRIGHT JOIN
と省略して書くことも可能です。
実行結果
id | name | department_id | id | name |
---|---|---|---|---|
1 | 山田 | 3 | 3 | 企画部 |
2 | 鈴木 | 4 | 4 | 経理部 |
3 | 佐藤 | 1 | 1 | 営業部 |
5 | 丸山 | 1 | 1 | 営業部 |
NULL | NULL | NULL | 2 | 人事部 |
NULL | NULL | NULL | 5 | 開発部 |
departmentテーブルを起点にしてemployeeテーブルを結合することができました。
departmentテーブルのid
が2
と5
の値はemployeeテーブルは存在しないため、NULL
が保存されています。
FULL OUTER JOIN
テーブルAとテーブルBの全て
FULL OUTER JOINは両者総取りです。
下記3点に該当するレコードを取得します。
- テーブルAとテーブルBのカラムの値が一致するレコード
- テーブルAには存在して、テーブルBのカラムには値が存在しないレコード
- テーブルAには存在せず、テーブルBのカラムには値が存在するレコード
どちらか一つのテーブルにしか存在しない値がある場合は、もう一方のカラムにはNULL
が保存されます。
※FULL OUTER JOIN
はMySQLなど一部のデータベースでは対応していないためご注意ください。
FULL OUTER JOIN
の基本構文は下記です。
SELECT カラム名
FROM テーブル名1
FULL OUTER JOIN テーブル名2
ON 結合の条件;
検索クエリ
employeeテーブルにdepartmentテーブルを完全外部結合(FULL OUTER JOIN)して取得する
SELECT *
FROM employee
FULL OUTER JOIN department
ON employee.department_id = department.id;
また、FULL OUTER JOIN
はFULL JOIN
と省略して書くことも可能です。
実行結果
id | name | department_id | id | name |
---|---|---|---|---|
1 | 山田 | 3 | 3 | 企画部 |
2 | 鈴木 | 4 | 4 | 経理部 |
3 | 佐藤 | 1 | 1 | 営業部 |
4 | 佐々木 | 6 | NULL | NULL |
5 | 丸山 | 1 | 1 | 営業部 |
NULL | NULL | NULL | 2 | 人事部 |
NULL | NULL | NULL | 5 | 開発部 |
employeeテーブルとdepartmentテーブルを完全外部結合することができました。
employeeテーブルのdepartment_id
が6
の値はdepartmentテーブルには存在しないためNULL
が保存されています。一方で、departmentテーブルのid
が2
と5
の値はemployeeテーブルには存在しないため、NULL
が保存されています。
このように、LEFT OUTER JOIN
とRIGHT OUTER JOIN
を足し合わせたものがFULL OUTER JOIN
と覚えておきましょう。
SQLのクロス結合「CROSS JOIN」
最後に、クロス結合について見ていきます。あまり実践で使うことは多くないので、ざっくり把握でもOKです。
テーブルAとテーブルBの全ての組み合わせ
クロス結合は、値の一致などは特に考えず、全てのレコードの組み合わせを取得する結合方法です。よって、実行結果のレコード数は膨大になります。
CROSS JOIN
の基本構文が下記です。
SELECT カラム名
FROM テーブル名1
CROSS JOIN テーブル名2;
全てのレコードの組み合わせなので、他のJOIN句の時のようにON
で条件指定をする必要がありません。
検索クエリ
SELECT *
FROM employee
CROSS JOIN department;
実行結果
id | name | department_id | id | name |
---|---|---|---|---|
1 | 山田 | 3 | 1 | 営業部 |
2 | 鈴木 | 4 | 1 | 営業部 |
3 | 佐藤 | 1 | 1 | 営業部 |
4 | 佐々木 | 6 | 1 | 営業部 |
5 | 丸山 | 1 | 1 | 営業部 |
1 | 山田 | 3 | 2 | 人事部 |
. . . | . . . | . . . | . . . | . . . |
右2列を見てみると、全てid
が1
の営業部
の情報になっています。まずは、departmentテーブルのid
が1
を起点にしてemployeeテーブルの全ての組み合わせを取得しているのです。
これが、2
の人事部
の場合、3
の企画部
の場合、…という形で全パターンを取得してきます。
実践でよく使うのはINNER JOIN
とLEFT OUTER JOIN
ここまで、5種類の結合を説明してきましたが、実際のデータ分析でよく使うのはINNER JOIN
とLEFT OUTER JOIN
です。
INNER JOIN
の使いどころ
テーブルを組み合わせて表示したい時に有効なので、実践で最も使われる結合です。
例えば、従業員がどの部署に所属しているかを把握したい時に、従業員を管理するテーブルと部署を管理するテーブルをINNER JOIN
を使って結合することで、一覧を取得できます。
LEFT OUTER JOIN
の使いどころ
一つの情報を元に、全てのパターンを炙り出したい時に有効です。
例えば、ユーザーに一斉にアンケート回答をお願いしたとします。アンケート結果を分析するために、アンケートを管理するテーブルを起点にユーザーを管理するテーブルをLEFT OUTER JOIN
することで、アンケートに回答していないユーザーにはNULLが保存されます。
誰がアンケートに回答していないか一目瞭然ということです。
この2つの結合方法については、必要になった時すぐに使えるように習得しておくことをおすすめします。
内容のまとめ
- SQLのテーブル結合とは、文字通り複数のテーブルを結合すること
- SQLで使える結合は5種類存在する
- 内部結合の
INNER JOIN
は、テーブルAとテーブルBのカラムの値が一致するレコードのみを取得する - 外部結合には、左外部結合の
LEFT OUTER JOIN
、右外部結合のRIGHT OUTER JOIN
、完全外部結合のFULL OUTER JOIN
の3種類がある - 左外部結合の
LEFT OUTER JOIN
は、テーブルAのレコードを全て取得した上で、テーブルBのカラムの値が一致するレコードも取得する - 右外部結合の
RIGHT OUTER JOIN
は、テーブルBのレコードを全て取得した上で、テーブルAのカラムの値が一致するレコードも取得する - 完全外部結合の
FULL OUTER JOIN
は、テーブルA・テーブルBそれぞれのレコードを全て取得した上で、テーブルAとテーブルBのカラムの値が一致するレコードも取得する - 外部結合の3つはそれぞれ
OUTER
を省略することができる - クロス結合の
CROSS JOIN
はテーブルAとテーブルBの全てのレコードの組み合わせを取得するため、実行結果のデータ量が膨大になる - 実践でよく使う結合方法は、
INNER JOIN
とLEFT OUTER JOIN
の2つ