【MySQL】外部結合(LEFT JOIN / RIGHT JOIN) - テーブル結合

【MySQL】外部結合(LEFT JOIN / RIGHT JOIN) - テーブル結合

MySQLの外部結合について解説します。

検証環境

外部結合

外部結合は“複数テーブルを繋げて1つの表データを作成すること”です。

各テーブルのカラムについて、値が同じレコード同士を繋げます。

内部結合と異なり、結合しなかったレコードも表示されます。

次のshopsテーブルとitemsテーブルで具体例を示します。

/* shopsテーブル */
+----+--------------+
| id | name         |
+----+--------------+
|  1 | Fruits Shop  |
|  2 | Food Shop    |
|  3 | Dessert Shop |
+----+--------------+

/* itemsテーブル */
+----+-----------+-------+-------+---------+
| id | name      | price | stock | shop_id |
+----+-----------+-------+-------+---------+
|  1 | Apple     |   200 |    10 |       1 |
|  2 | Orange    |   150 |     3 |       1 |
|  3 | Pineapple |  1100 |     3 |       2 |
|  4 | Grapes    |  3500 |     1 |       2 |
+----+-----------+-------+-------+---------+

itemsテーブルはshop_idカラムでshopsテーブルのidカラムの値を保持します。

この2カラムで外部結合した結果は次の表です。

+----+--------------+------+-----------+-------+-------+---------+
| id | name         | id   | name      | price | stock | shop_id |
+----+--------------+------+-----------+-------+-------+---------+
|  1 | Fruits Shop  |    1 | Apple     |   200 |    10 |       1 |
|  1 | Fruits Shop  |    2 | Orange    |   150 |     3 |       1 |
|  2 | Food Shop    |    3 | Pineapple |  1100 |     3 |       2 |
|  2 | Food Shop    |    4 | Grapes    |  3500 |     1 |       2 |
|  3 | Dessert Shop | NULL | NULL      |  NULL |  NULL |    NULL |
+----+--------------+------+-----------+-------+-------+---------+

各テーブルのレコードが2カラムを基点に結合されています。

shopsテーブルのidが3のレコードは、itemsテーブルのshop_idカラムに存在しないため、itemsテーブルのカラム値はNULLが表示されます。


また、外部結合には左外部結合と右外部結合があります。

2つのテーブルを横に並べたとき、左を軸にするのが左外部結合、右を軸にするのが右外部結合です。

上記具体例はshopsテーブル(左)、itemsテーブル(右)とした時、左外部結合になります。

LEFT JOIN

MySQLで左外部結合を実現するにはLEFT JOIN句を使用します。

基本構文

SELECT 表示カラム FROM テーブルA LEFT JOIN テーブルB ON テーブルA.カラム = テーブルB.カラム

LEFT JOIN句はSELECT文と合わせて使用します。

LEFT JOIN テーブルB ON テーブルA.カラム = テーブルB.カラムがLEFT JOIN句の部分です。

基本的には内部結合のINNER JOIN句と同様で、SELECT文のテーブルAに対して外部結合するテーブルBと、結合の基点となる各カラムをテーブルA.カラムテーブルB.カラムの形式で記述します。

サンプル

mysql> SELECT * FROM shops;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | Fruits Shop  |
|  2 | Food Shop    |
|  3 | Dessert Shop |
+----+--------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM items;
+----+-----------+-------+-------+---------+
| id | name      | price | stock | shop_id |
+----+-----------+-------+-------+---------+
|  1 | Apple     |   200 |    10 |       1 |
|  2 | Orange    |   150 |     3 |       1 |
|  3 | Pineapple |  1100 |     3 |       2 |
|  4 | Grapes    |  3500 |     1 |       2 |
+----+-----------+-------+-------+---------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM shops
    ___ih_hl_start
    -> LEFT JOIN items ON shops.id = items.shop_id;
    ___ih_hl_end
+----+--------------+------+-----------+-------+-------+---------+
| id | name         | id   | name      | price | stock | shop_id |
+----+--------------+------+-----------+-------+-------+---------+
|  1 | Fruits Shop  |    1 | Apple     |   200 |    10 |       1 |
|  1 | Fruits Shop  |    2 | Orange    |   150 |     3 |       1 |
|  2 | Food Shop    |    3 | Pineapple |  1100 |     3 |       2 |
|  2 | Food Shop    |    4 | Grapes    |  3500 |     1 |       2 |
|  3 | Dessert Shop | NULL | NULL      |  NULL |  NULL |    NULL |
+----+--------------+------+-----------+-------+-------+---------+
5 rows in set (0.00 sec)

23行目が左外部結合(LEFT JOIN句)の部分です。

shopsテーブル(左)のidカラムに対して、itemsテーブル(右)のshop_idカラムの値が同じレコードを結合しています。

上記サンプルでは*によって全てのカラムを表示していますが、通常のSELECT文と同様に任意のカラムのみ表示することも可能です。

2つのテーブルでカラム名が重複している場合は、どちらのテーブルのカラムか分かるようにテーブル名とカラム名をドット(.)で繋げ、テーブル名.カラム名のように明示的に記述します。

mysql> SELECT shops.name, items.name, price, stock FROM shops 
    -> LEFT JOIN items ON shops.id = items.shop_id;
+--------------+-----------+-------+-------+
| name         | name      | price | stock |
+--------------+-----------+-------+-------+
| Fruits Shop  | Apple     |   200 |    10 |
| Fruits Shop  | Orange    |   150 |     3 |
| Food Shop    | Pineapple |  1100 |     3 |
| Food Shop    | Grapes    |  3500 |     1 |
| Dessert Shop | NULL      |  NULL |  NULL |
+--------------+-----------+-------+-------+
5 rows in set (0.01 sec)

RIGHT JOIN

MySQLで右外部結合を実現するにはRIGHT JOIN句を使用します。

基本構文

SELECT 表示カラム FROM テーブルA RIGHT JOIN テーブルB ON テーブルA.カラム = テーブルB.カラム

RIGHT JOIN句はSELECT文と合わせて使用します。

基本的にはLEFT JOIN句と同じで、RIGHTLEFTの違いになります。

サンプル

mysql> SELECT * FROM shops;
+----+--------------+
| id | name         |
+----+--------------+
|  1 | Fruits Shop  |
|  2 | Food Shop    |
|  3 | Dessert Shop |
+----+--------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM items;
+----+-----------+-------+-------+---------+
| id | name      | price | stock | shop_id |
+----+-----------+-------+-------+---------+
|  1 | Apple     |   200 |    10 |       1 |
|  2 | Orange    |   150 |     3 |       1 |
|  3 | Pineapple |  1100 |     3 |       2 |
|  4 | Grapes    |  3500 |     1 |       2 |
+----+-----------+-------+-------+---------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM shops
    ___ih_hl_start
    -> RIGHT JOIN items ON shops.id = items.shop_id;
    ___ih_hl_end
+------+-------------+----+-----------+-------+-------+---------+
| id   | name        | id | name      | price | stock | shop_id |
+------+-------------+----+-----------+-------+-------+---------+
|    1 | Fruits Shop |  1 | Apple     |   200 |    10 |       1 |
|    1 | Fruits Shop |  2 | Orange    |   150 |     3 |       1 |
|    2 | Food Shop   |  3 | Pineapple |  1100 |     3 |       2 |
|    2 | Food Shop   |  4 | Grapes    |  3500 |     1 |       2 |
+------+-------------+----+-----------+-------+-------+---------+
4 rows in set (0.00 sec)

23行目が右外部結合(RIGHT JOIN句)の部分です。

itemsテーブル(右)のshop_idカラムを基準にshopsテーブル(左)のidカラムの値が同じレコードを結合しています。

上記サンプルでは*によって全てのカラムを表示していますが、通常のSELECT文と同様に任意のカラムのみ表示することも可能です。

2つのテーブルでカラム名が重複している場合もLEFT JOIN句と同様に明示的に記述します。

mysql> SELECT shops.name, items.name, price, stock FROM shops
    -> RIGHT JOIN items ON shops.id = items.shop_id;
+-------------+-----------+-------+-------+
| name        | name      | price | stock |
+-------------+-----------+-------+-------+
| Fruits Shop | Apple     |   200 |    10 |
| Fruits Shop | Orange    |   150 |     3 |
| Food Shop   | Pineapple |  1100 |     3 |
| Food Shop   | Grapes    |  3500 |     1 |
+-------------+-----------+-------+-------+
4 rows in set (0.00 sec)