inner joinで条件を設定しない時


inner join で条件を指定しないとどうなるか

inner join句は結合するテーブル同士でどのキーで結合するかを指定する。
指定しなくてもクエリは実行される(実行エラーにならない)が、挙動が変わる。

テスト用テーブル

customers (顧客テーブル)

id customer_name
1 hirata
2 kanazawa
3 fukuda

products (商品テーブル 名称と金額のみ)

id product_name price
1 pencil 100
2 eraser 120
3 note 150

order_history (注文履歴、注文数などは省略)

id customer_id product_id date
1 1 1 2021-06-07
2 2 1 2021-06-07
3 2 2 2021-06-07
4 2 3 2021-06-08
5 3 1 2021-06-05
6 3 3 2021-06-08

基本的な(left) inner join句の書き方

-- 注文履歴と商品テーブルと顧客テーブルを結合
select * from order_history o inner join products p on o.product_id = p.id 

result

o.id o.customer_id o.product_id o.order_date p.id p.product_name p.price c.id c.customer_name
1 1 1 2021-06-07 1 pencil 100 1 hirata
2 2 1 2021-06-07 1 pencil 100 2 kanazawa
3 2 2 2021-06-07 2 eraser 120 2 kanazawa
4 2 3 2021-06-08 3 note 150 2 kanazawa
5 3 1 2021-06-05 1 pencil 100 3 fukuda
6 3 3 2021-06-08 3 note 150 3 fukuda

注文履歴をベースに、

結合条件を指定しない場合

select * from order_history o inner join products p inner join customers c;

result

o.id o.customer_id o.product_id o.order_date p.id p.product_name p.price c.id c.customer_name
1 1 1 2021-06-07 1 pencil 100 1 hirata
1 1 1 2021-06-07 2 eraser 120 1 hirata
1 1 1 2021-06-07 3 note 150 1 hirata
1 1 1 2021-06-07 1 pencil 100 2 kanazawa
1 1 1 2021-06-07 2 eraser 120 2 kanazawa
1 1 1 2021-06-07 3 note 150 2 kanazawa
1 1 1 2021-06-07 1 pencil 100 3 fukuda
1 1 1 2021-06-07 2 eraser 120 3 fukuda
1 1 1 2021-06-07 3 note 150 3 fukuda
2 2 1 2021-06-07 1 pencil 100 1 hirata
2 2 1 2021-06-07 2 eraser 120 1 hirata
2 2 1 2021-06-07 3 note 150 1 hirata
2 2 1 2021-06-07 1 pencil 100 2 kanazawa
2 2 1 2021-06-07 2 eraser 120 2 kanazawa

.......

と、結果が大量になるので途中までだが、結合条件を指定しないと全行で結合してしまう。
これはcross join指定をしているのと同じ。

select * from order_history o cross join products p cross join customers c

この挙動が便利な時(cross join)

全組み合わせが確認できるので、それなりに便利。
私は、日付ごとに集計結果を出力したい時で、「集計結果にならない日付も出力したい場合」に全ての日付でテーブルを作成する時に使用したりします。
例のorder_historyでは、6月5日、7日、8日のデータがあるため、これで商品の日付ごとを集計すると6日のデータが出力されない。

select product_id ,order_date, sum(price) from order_history o inner join products p on p.id = o.product_id group by product_id ,order_date;
product_id order_date sum(price)
1 2021-06-05 100
1 2021-06-07 200
2 2021-06-07 120
3 2021-06-08 300

cross joinで商品✕日付の全組み合わせを出力しておいて、それに結果を紐付けると結果の無い日付も出力対象になる。

select p.id, p.product_name, d, order_date, sum_price from products p cross join
(select
date_format(date_add('2021-06-04', interval td.generate_series day), '%Y-%m-%d') as d
from
(
SELECT 0 generate_series FROM DUAL WHERE (@num:=1-1)*0 UNION ALL
SELECT @num:=@num+1 FROM `information_schema`.COLUMNS LIMIT 7
) as td
) date_table
left join 
(select product_id ,order_date, sum(price) as sum_price from order_history o inner join products p on p.id = o.product_id group by product_id ,order_date) ledger
on ledger.product_id = p.id and ledger.order_date = date_table.d
order by p.id, d
;
id product_name d order_date sum_price
1 pencil 2021-06-05 2021-06-05 100
1 pencil 2021-06-06
1 pencil 2021-06-07 2021-06-07 200
1 pencil 2021-06-08
1 pencil 2021-06-09
1 pencil 2021-06-10
1 pencil 2021-06-11
2 eraser 2021-06-05
2 eraser 2021-06-06
2 eraser 2021-06-07 2021-06-07 120
2 eraser 2021-06-08
2 eraser 2021-06-09
2 eraser 2021-06-10
2 eraser 2021-06-11
3 note 2021-06-05
3 note 2021-06-06
3 note 2021-06-07
3 note 2021-06-08 2021-06-08 300
3 note 2021-06-09
3 note 2021-06-10
3 note 2021-06-11

MySQL8.0はWindow関数も使えたり集計関数も増えているので、5.7までで無理やりやるとこんな感じというところはありますが。
ともあれ、たまにSQL書こうとすると間違ったりするので注意。