外部結合 OUTER JOIN
テーブルの結合には内部結合と外部結合があります。
テーブルの結合においてどちらか一方のデータをすべて網羅したいときには外部結合( OUTER JOIN )
を使用します。
SELECT * FROM goods JOIN sales_slip ;
上記のようにJOIN
のみでは内部結合として処理されます。外部結合の場合はOUTER JOIN
と明記する必要があります。
SELECT * FROM goods AS g LEFT OUTER JOIN sales_slip AS s ON g.id = s.goods_id;
さらにOUTER JOIN
の前にLEFT
またはRIGHT
といった先のテーブルの内容を優先するのか後のテーブルのデータを優先するのかと、ON
による結合条件を設定しないとエラーになります。
内部結合と外部結合の違いは、内部結合は片方のテーブルデータがない組み合わせは除外されます。
外部結合は、LEFT
またはRIGHT
で一方のテーブルデータを網羅するようにします。
例えば以下の例では商品名マスタと売上を外部結合しています。LEFT
によって商品マスタのすべてのデータを網羅します。売上に商品名がない場合は NULL で表現されます。
> SELECT * FROM goods g LEFT OUTER JOIN sales_slip s ON g.id=s.goods_id;
+----+----------------+------------+------+---------------------+----------+------------+--------+---------+
| id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id |
+----+----------------+------------+------+---------------------+----------+------------+--------+---------+
| 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 |
| 1 | candy | 3 | 1 | 2023-10-29 07:17:00 | 1 | 3 | 100 | 1 |
| 2 | snack | 5 | 3 | 2023-09-28 22:42:10 | 2 | 5 | 30 | 1 |
| 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 |
| 3 | chocolate | 8 | 5 | 2023-09-28 22:42:53 | 3 | 10 | 10 | 3 |
| 4 | ice | 8 | NULL | NULL | NULL | NULL | NULL | NULL |
| 5 | lollipop candy | 15 | NULL | NULL | NULL | NULL | NULL | NULL |
+----+----------------+------------+------+---------------------+----------+------------+--------+---------+
優先された商品マスタのデータはすべて網羅する形になり、売れていない商品が分かりやすくなります。
ページ内 Index
例のデータについて
以降の例では、テーブル
ページの外部キー制約( FOREIGN KEY )
の作成例で使用したデータを使用しています。
以下のようなデータです。
SELECT * FROM goods; +----+----------------+------------+ | id | name | unit_price | +----+----------------+------------+ | 1 | candy | 3 | | 2 | snack | 5 | | 3 | chocolate | 8 | | 4 | ice | 8 | | 5 | lollipop candy | 15 | +----+----------------+------------+ ... select * from sales_slip; +----+---------------------+----------+------------+--------+ | id | date_time | goods_id | unit_price | amount | +----+---------------------+----------+------------+--------+ | 1 | 2023-09-26 22:29:57 | 1 | 3 | 100 | | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | | 3 | 2023-09-28 22:42:10 | 2 | 5 | 30 | | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | | 5 | 2023-09-28 22:42:53 | 3 | 10 | 10 | +----+---------------------+----------+------------+--------+ ...
OUTER JOIN
外部結合ではOUTER JOIN
句を使用します。さらにLEFT
またはRIGHT
と組み合わせ条件であるON
句も必要になります。
LEFT
またはRIGHT
はすべてのデータを網羅したい側のテーブルを指定します
例えば、以下のように商品マスタと売上データを結合しているのですが、商品マスタのデータをすべて網羅しています。
このことで各商品の販売数を知ることができ、また売れていない商品を知ることができます。
> SELECT * FROM goods g LEFT OUTER JOIN sales_slip s ON g.id=s.goods_id; +----+----------------+------------+------+---------------------+----------+------------+--------+---------+ | id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id | +----+----------------+------------+------+---------------------+----------+------------+--------+---------+ | 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 | | 1 | candy | 3 | 1 | 2023-10-29 07:17:00 | 1 | 3 | 100 | 1 | | 2 | snack | 5 | 3 | 2023-09-28 22:42:10 | 2 | 5 | 30 | 1 | | 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 | | 3 | chocolate | 8 | 5 | 2023-09-28 22:42:53 | 3 | 10 | 10 | 3 | | 4 | ice | 8 | NULL | NULL | NULL | NULL | NULL | NULL | | 5 | lollipop candy | 15 | NULL | NULL | NULL | NULL | NULL | NULL | +----+----------------+------------+------+---------------------+----------+------------+--------+---------+
amount が販売数ですが、NULL で表示された商品は販売データがないことを示しています。
この結果を GROUP BY で商品ごとにグループ化すれば商品ごとの販売数を知ることができます。
外部結合では必ずOUTER JOIN
句を使用します。JOIN
だけでは内部結合を示し、すべての組み合わせを網羅します。
内部結合では片方のテーブルデータがない場合はその行は除外されます。
例えば上記の外部結合を内部結合に換えると以下のような結果になります。
SELECT * FROM goods AS g JOIN sales_slip AS s ON g.id = s.goods_id;
+----+-----------+------------+----+---------------------+----------+------------+--------+---------+
| id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id |
+----+-----------+------------+----+---------------------+----------+------------+--------+---------+
| 1 | candy | 3 | 1 | 2023-10-29 07:17:00 | 1 | 3 | 100 | 1 |
| 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 |
| 2 | snack | 5 | 3 | 2023-09-28 22:42:10 | 2 | 5 | 30 | 1 |
| 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 |
| 3 | chocolate | 8 | 5 | 2023-09-28 22:42:53 | 3 | 10 | 10 | 3 |
+----+-----------+------------+----+---------------------+----------+------------+--------+---------+
内部結合では商品マスタにデータがあっても売上にないデータは除外されています。内部結合では、ice
とlollipop candy
が網羅されていません。
内部結合についてはテーブルの結合 JOIN
ページを参照してください。
RIGHT OUTER JOIN
上記のLEFT OUTER JOIN
はこの句の左側のテーブルのデータをすべて網羅します。
右側を中心に外部結合をすることもでき、その場合はRIGHT OUTER JOIN
とします。
> SELECT * FROM goods g
RIGHT OUTER JOIN sales_slip s
ON g.id=s.goods_id;
+------+-----------+------------+----+---------------------+----------+------------+--------+---------+
| id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id |
+------+-----------+------------+----+---------------------+----------+------------+--------+---------+
| 1 | candy | 3 | 1 | 2023-10-29 07:17:00 | 1 | 3 | 100 | 1 |
| 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 |
| 2 | snack | 5 | 3 | 2023-09-28 22:42:10 | 2 | 5 | 30 | 1 |
| 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 |
| 3 | chocolate | 8 | 5 | 2023-09-28 22:42:53 | 3 | 10 | 10 | 3 |
+------+-----------+------------+----+---------------------+----------+------------+--------+---------+
上記の例でのRIGHT OUTER JOIN
では売上データをすべて網羅します。売上データにあって商品マスタにはないデータがないため、ただ売上データを閲覧する形になっています。
ON 結合条件
外部結合 OUTER JOIN では ON 句が必要になります。ON 句はテーブルの結合条件を付加するためのものです。
SELECT * FROM goods AS g LEFT OUTER JOIN sales_slip s
ON g.id = s.goods_id;
+----+----------------+------------+------+---------------------+----------+------------+--------+---------+
| id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id |
+----+----------------+------------+------+---------------------+----------+------------+--------+---------+
| 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 |
| 1 | candy | 3 | 1 | 2023-10-29 07:17:00 | 1 | 3 | 100 | 1 |
| 2 | snack | 5 | 3 | 2023-09-28 22:42:10 | 2 | 5 | 30 | 1 |
| 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 |
| 3 | chocolate | 8 | 5 | 2023-09-28 22:42:53 | 3 | 10 | 10 | 3 |
| 4 | ice | 8 | NULL | NULL | NULL | NULL | NULL | NULL |
| 5 | lollipop candy | 15 | NULL | NULL | NULL | NULL | NULL | NULL |
+----+----------------+------------+------+---------------------+----------+------------+--------+---------+
非等結合
ON 句における条件でイコール=
で評価される場合は等結合といいます。
範囲による条件も指定することができます。範囲による結合は非等結合といいます。
以下の例は非等結合ができることを示しているだけで意味がありません。
SELECT * FROM goods AS g LEFT OUTER JOIN sales_slip AS s
ON g.id >= s.goods_id;
ON 句と WHERE 句
テーブル結合に WHERE 句による抽出を加えるとその条件による行データのみが取得できます。
SELECT * FROM goods AS g LEFT OUTER JOIN sales_slip AS s
ON g.id = s.goods_id
WHERE amount >= 50;
+----+-------+------------+----+---------------------+----------+------------+--------+---------+
| id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id |
+----+-------+------------+----+---------------------+----------+------------+--------+---------+
| 1 | candy | 3 | 1 | 2023-10-05 20:46:53 | 1 | 3 | 100 | 1 |
| 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 |
| 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 |
+----+-------+------------+----+---------------------+----------+------------+--------+---------+
このことは ON 句で AND を使用しても同じことが起きます。
> SELECT * FROM goods AS g LEFT OUTER JOIN sales_slip AS s
ON g.id = s.goods_id
AND amount >= 50;
+----+-------+------------+----+---------------------+----------+------------+--------+---------+
| id | name | unit_price | id | date_time | goods_id | unit_price | amount | user_id |
+----+-------+------------+----+---------------------+----------+------------+--------+---------+
| 1 | candy | 3 | 1 | 2023-10-05 20:46:53 | 1 | 3 | 100 | 1 |
| 2 | snack | 5 | 2 | 2023-09-26 22:29:58 | 2 | 8 | 50 | 1 |
| 1 | candy | 3 | 4 | 2023-09-28 22:42:10 | 1 | 5 | 80 | 2 |
+----+-------+------------+----+---------------------+----------+------------+--------+---------+
ただし、処理の順番に違いがあります。同じ結果が得られるのですがコードの意味が目的とした手段に準じているかが大事です。
