SQLのSELECT文で複数のテーブルを結合するJOIN (INNER LEFT RIGHT FULL CROSS)

SQLのSELECT文を使うと、テーブルなどのオブジェクトからデータ(レコード)を取得することができます。

本サイトでは、以前に以下の記事でSELECT文を使った基本的なデータの取得についてご紹介しました。

SQLのSELECT文でデータ(レコード)を取得(抽出)する
SQLを使用すると、データベースに対して様々な命令を与えることができます。データ(レコード)を抽出したり、データを追加・変更・削除したり、デ...

上記の記事では、1つのテーブルからデータを取得する基本的なSELECT文について記載していますが、2つ以上の複数のテーブルからデータを取得したい場合があります。
例えば、ユーザー情報を管理ししているユーザーテーブルに性別情報「1: 男性」「2: 女性」「3: その他」が登録されており、性別の名称は別のマスタテーブルで管理されているとします。
ユーザーテーブルには、性別の種類を表す数値のみ登録されているので、性別の名称(男性、女性、その他)を取得する場合は、性別マスタテーブルも併せて参照する必要があります。

通常データベースのテーブルは、データを管理しやすいようにテーブルを複数に分けて管理します。
データベースでは、いろいろな種類のデータが集まった1つのテーブルで管理するよりも、効率よくデータを分けて管理した方が安全で確実であり、パフォーマンス面でも優れています。

複数に分けたテーブルのデータは人に見せる時に結合することで、人間にわかりやすく表示することができますので、管理する際は分けておいた方が様々な面で都合がよいためです。

そこで今回は、複数のテーブルからデータを結合して取得する方法について紹介したいと思います。

データの取得に使用するサンプルテーブル

本記事では、データを取得するためのサンプルテーブルとして、以下のテーブルを使用します。

テーブル定義

テーブル名は「スタッフ」とします。従業員の情報を管理する想定のテーブルになります。

テーブルの列には、主キー(プライマリーキー)となる「ID」、氏名を管理するための「姓」と「名」、性別を「1: 男性」「2: 女性」「3: その他」で管理する性別、血液型を「1: A型」「2: B型」「3: O型」「4: AB型」で管理するための「血液型」、所属する部署を管理する「部署」の6つの列を作成します。

マスタテーブルは、スタッフテーブルの「性別」に関連するマスタテーブルを「性別」、「血液型」に関連するマスタテーブルを「血液型」、部署に関連するマスタテーブルを「部署」とします
マスタテーブルには、IDまたはコード値と名称を管理する2つの列を作成します。性別マスタと血液型マスタはIDと名称、部署マスタはコードと名称の列を持ちます。

スタッフ
列名 データ型 主キー
ID int
varchar(20)
varchar(20)
性別 int
血液型 int
部署 varchar(3)
性別マスタ
列名 データ型 主キー
ID int
名称 varchar(20)
血液型マスタ
列名 データ型 主キー
ID int
名称 varchar(20)
部署マスタ
列名 データ型 主キー
コード varchar(3)
名称 varchar(20)

テーブルを作成するCREATE文のSQL

サンプルとして使用するユーザーテーブルを作成するSQLは次のようになります。

スタッフ

性別マスタ

血液型マスタ

部署マスタ

上記のSQLを実行するとテーブルが作成されます。

テーブルにレコードを挿入するINSERT文のSQL

スタッフ

性別マスタ

血液型マスタ

部署マスタ

上記のSQLを実行するとテーブルにデータ(レコード)が挿入(登録)されます。

各テーブルへのデータのインサートは、複数のレコードを1回のSQLで一括挿入する形式で記述しています。
1回のINSERTで複数行のレコードをテーブルに一括で挿入する方法については、以下の記事を参照してください。

1回のINSERT(インサートSQL)で複数行のレコードを一括挿入(追加)する
SQLServerやMySQLなどのデータベースで、テーブルにレコードをINSERT文使用して追加するには、通常は以下のように記述します。 ...

複数のテーブルを結合する

複数のテーブルからデータを取得する場合は、テーブルを結合します。
SQLでテーブルを結合する場合は、JOINキーワードを使用します。
JOINキーワード使ったテーブルの結合には、INNER JOIN、LEFT [OUTER] JOIN、RIGHT [OUTER] JOIN、FULL [OUTER] JOIN、CROSS JOINがあります。

以下にそれぞれの結合方法について記載します。
(テーブルの結合は2つ以上できますが、ここでは説明のため2つのテーブルに絞って記載していきます。)

INNER JOIN 内部結合

INNER JOINでは、結合する2つのテーブルを特定のキー(列)の値で紐づけて、一致するレコードのみを抽出します。

たとえば、サンプルのスタッフテーブルの「性別」列と、性別マスタテーブルの「ID」を紐づけてINNER JOINでレコードを抽出すると、結果として得られる表(データ)は、以下のようになります。

INNER JOINで得られる結果表

No. スタッフID 性別ID 性別名称
1 1000 足立 花子 2 女性
2 1001 我孫子 一郎 1 男性
3 1002 御陵 次郎 1 男性
4 2000 反町 梅子 2 女性
5 2002 四十万 三四郎 1 男性
6 2003 相模 菊枝 2 女性
7 3000 八万 五郎 1 男性
8 3002 出石 桜花 2 女性
9 5000 蒜山 2 女性

上記の表は、スタッフテーブルの「性別(ID)」列の値と、性別マスタテーブルの「(性別)ID」列の値が一致するレコードを対応させ、1つの行に結合してスタッフのIDと氏名(姓と名)、性別のIDと名称の計5つの情報を抜き出しています。

この結果表を得るためのSQLは次のようになります。

INNER JOINでテーブルを結合するSQL文

FROM句でスタッフテーブルと性別マスタテーブルをINNER JOINでつなぎます。
テーブルの結合にはJOINキーワードを使用します。INNER JOINの前後(左右または上下)にでテーブルを指定し、結合する条件をONキーワードを使って指定します。
上記のSQLでは見やすいように、テーブル名とJOIN句を改行して記述しているのでテーブルが上下に並んでいますが、改行せずに記述するとJOIN句を挟んでテーブル名が左右に並びます。

スタッフテーブルがJOIN句の左側に、性別マスタテーブルがJOIN句の右側に記述されています。

INNER JOINによるテーブルの結合イメージを図で表すと以下のようになります。

INNER JOINでテーブルを結合したイメージ図

INNER JOIN 内部結合
イメージ図の○は、結合するテーブルを表わしています。

INNER JOINでは、結合条件で結合した結果、両方のテーブルに存在する部分が一致するレコードのみ抽出対象になります。
イメージ図では、それぞれのテーブルを重ね合わせて、両方のテーブル(○)が重なる部分に色がついています。
この重なる部分が両方のテーブルの内側の部分になるので、INNER JOINは内部結合と呼ばれます。

INNER JOINの「INNER」の部分は省略することができます。
ですので、以下のSQLの結合結果はINNER JOINでの結合結果と同じになります。

本ブログでは、内部結合を行う際には、INNERを省略せずに記述することをお勧めします。
世の中にはテーブルの結合にJOINのみ記述されている場合に、どのような結合であるかがわからない人が数多くいらっしゃいます。
また、INNERを記述することで、後で説明する他の結合方法との区別もつきやすくなります。
ちなみに私は、必ず「INNER JOIN」と記述するようにしています。

LEFT OUTER JOIN 左外部結合

LEFT OUTER JOINでは、INNER JOINと同様に結合する2つのテーブルを特定のキー(列)の値で紐づけます。
INNER JOINの場合はキー(列)の値が一致するレコードのみが抽出されましたが、LEFT OUTER JOINでは、JOIN句の左側テーブル(JOIN句の前に記述するテーブル)のレコードはすべて抽出されます。

INNER JOINの場合と同様に、スタッフテーブルと性別マスタテーブルを結合した結果表を以下に示します。

LEFT OUTER JOINで得られる結果表

スタッフID 性別ID 性別名称
1000 足立 花子 2 女性
1001 我孫子 一郎 1 男性
1002 御陵 次郎 1 男性
2000 反町 梅子 2 女性
2001 飛鳥 紅葉 NULL NULL
2002 四十万 三四郎 1 男性
2003 相模 菊枝 2 女性
3000 八万 五郎 1 男性
3001 土々呂 六郎 0 NULL
3002 出石 桜花 2 女性
5000 蒜山 2 女性

実行結果の表を見ると、INNER JOINの時はなかった行(スタッフIDが2001と3001)が取得されています。

LEFT OUTER JOINでは、左側のテーブルのレコードは、結合条件に一致しない場合でも抽出対象となり、結果表に含まれるためです。

上記の結果表を取得するためのSQLは次のようになります。

LEFT OUTER JOINでテーブルを結合するSQL文

スタッフテーブルがJOIN句の左側にあるので、スタッフテーブルのレコードは、性別列の値が性別マスタテーブルに存在しても、しなくても抽出されます。

LEFT OUTER JOINによるテーブルの結合イメージを図で表すと以下のようになります。

LEFT OUTER JOIN 左外部結合

LEFT OUTER JOINでは、結合条件による一致有無にかかわらず、左側(前側)のテーブルが優先して取得されますので、左外部結合と呼ばれます。

LEFT OUTER JOINの「OUTER」の部分は省略することができます。
ですので、以下のSQLの結合結果はLEFT OUTER JOINでの結合結果と同じになります。

本ブログでは、左外部結合を行う際には、OUTERを省略せずに記述することをお勧めします。
ちなみに私は、必ず「LEFT OUTER JOIN」と記述するようにしています。

RIGHT OUTER JOIN 右外部結合

RIGHT OUTER JOINは、方向(左右)がLEFT OUTER JOINの逆になります。

RIGHT OUTER JOINによるテーブルの結合イメージを図で表すと以下のようになります。

RIGHT OUTER JOIN 右外部結合

RIGHT OUTER JOINでは、結合条件による一致有無にかかわらず、右側(後側)のテーブルが優先して取得されますので、右外部結合と呼ばれます。

LEFT OUTER JOINでスタッフテーブルと性別マスタを結合したSQL文のテーブルの左右を逆にして

と記述すれば、LEFT OUTER JOINの時と同じ結果表が得られます

スタッフテーブルをJOIN句の左側に記載し、性別マスタをJOIN句の右側に記載した以下のSQLですと

得られる結果表は次のようになります。

RIGHT OUTER JOINで得られる結果表

スタッフID 性別ID 性別名称
1001 我孫子 一郎 1 男性
1002 御陵 次郎 1 男性
2002 四十万 三四郎 1 男性
3000 八万 五郎 1 男性
1000 足立 花子 2 女性
2000 反町 梅子 2 女性
2003 相模 菊枝 2 女性
3002 出石 桜花 2 女性
5000 蒜山 2 女性
NULL NULL NULL NULL その他

JOIN句の右側に記述されたテーブルの行をすべて取得して、左側に記述されたテーブルから結合条件に一致する行を結合しますので、性別マスタテーブルの全レコードと、各レコードに紐づくスタッフテーブルのレコードが結合された結果表になります。

本ブログでは、右外部結合を行う際には、OUTERを省略せずに記述することをお勧めします。
ちなみに私は、必ず「RIGHT OUTER JOIN」と記述するようにしています。

RIGHT OUTER JOIN に関する補足

RIGHT OUTER JOINは右側のテーブルのレコードを優先してデータを取得しますが、この動作はLEFT OUTER JOINでもテーブルを記述する順序を変更することで、同じ結果(データ)を得ることができます。
SQL(プログラム)の可読性を向上させるという面では、RIGHT OUTER JOIN1は使用せずに、LEFT OUTER JOINで記述するように統一しておくことをおすすめします。

FULL OUTER JOIN 完全外部結合

テーブルを結合する外部結合には、LEFT OUTER JOIN、RIGHT OUTER JOINの他に、FULL OUTER JOINという結合方法があります。

FULL OUTER JOINによるテーブルの結合イメージを図で表すと以下のようになります。

FULL OUTER JOIN 完全外部結合

FULL OUTER JOINでは、左右両方のテーブルのレコードをすべて残して取得し、結合条件に一致する場合にレコードを結合します。
結合するテーブルの外部も含めてすべてのデータをが取得されるので、完全外部結合と呼ばれます。

以下にスタッフテーブルと性別マスタテーブルをFULL OUTER JOINで結合するSQL文と、SQL文を実行して得られる結果表を示します。

FULL OUTER JOINでテーブルを結合するSQL文

FULL OUTER JOINで得られる結果表

スタッフID 性別ID 性別名称
1000 足立 花子 2 女性
1001 我孫子 一郎 1 男性
1002 御陵 次郎 1 男性
2000 反町 梅子 2 女性
2001 飛鳥 紅葉 NULL NULL
2002 四十万 三四郎 1 男性
2003 相模 菊枝 2 女性
3000 八万 五郎 1 男性
3001 土々呂 六郎 0 NULL
3002 出石 桜花 2 女性
5000 蒜山 2 女性
NULL NULL NULL NULL その他

FULL OUTER JOINの「OUTER」の部分は、LEFT、RIGHTと同様に省略することができます。
ですので、以下のSQLの結合結果はFULL OUTER JOINでの結合結果と同じになります。

本ブログでは、完全外部結合を行う際には、OUTERを省略せずに記述することをお勧めします。
ちなみに私は、必ず「FULL OUTER JOIN」と記述するようにしています。

CROSS JOIN 交差結合

最後にJOINを使用した結合の中で、CROSS

CROSS JOINは名前にクロスとある通り、テーブルのレコード動詞をクロスして結合したレコードを結果として返します。

CROSS JOINでテーブルを結合したイメージ図

CROSS JOIN 交差結合

CROSS JOINで得られる結果表のイメージ図

CROSS JOIN 交差結合結果表

CROSS JOINは、左右のテーブルのすべての行の総当たりをクロス(交差)したレコードを返すので、交差結合と呼ばれます。

CROSS JOINでテーブルを結合するSQL文

CROSS JOINでは結合するそれぞれのテーブルすべての行同士の結合にになりますので、ON句で結合条件を指定する記述は必要ありません。

上記のSQL文の実行結果はレコードが多くなるので掲載しませんが、結合するテーブルの行数を乗算した件数になります。
Aテーブルの件数が11件、Bテーブルの件数が3件であれば、11×3=33件のレコードが返されます。

CROSS JOINによるデータの取得は、アプリケーションの作成などではあまり使いませんが、テストデータの作成のためにレコードを増殖する際などには非常に便利なので、覚えておいて損はないでしょう。

まとめ

本記事では、様々なテーブルの結合について紹介しました。
SQLのSELECT文で使用できるJOIN句には、INNER JOIN、LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN、CROSS JOINの5種類がありました。

このうちINNER JOINとLEFT OUTER JOINは非常によく使用する構文になります。

ぜひ皆さんもいろいろなテーブルの結合が使いこなせるようになって、システムの開発やアプリケーションの作成に役立ててください。