JOINで行が増える理由と重複チェック(件数確認・1対多の見分け方)
この記事で分かること
- JOIN後に「件数が合わない」「同じ行が何度も出る」とき、原因を切り分けられる
- 結合前と結合後の件数を確認する手順が身につく
- 1対多・多対多の関係を意識して、JOIN条件を足す・見直す判断ができる
結論:結合前後の件数を必ず確認する
JOINは「条件に合う組み合わせ」をすべて出します。1対多の「多」側を結合すると行数は増えます。意図した結合なら問題ありませんが、「条件不足で意図せず増えている」のか「1対多で増えているだけ」なのかを、結合前の各表の件数と結合後の件数で確認すると原因が絞れます。
最小例:結合すると行が増える
顧客(customers)と注文(orders)は 1対多 です。1人に注文が複数あるため、JOINすると行数は「注文の数」になります。
-- 結合後の件数は「注文の数」(顧客数より多くなりがち)
SELECT c.name, o.total
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.id;
- 意図どおり: 「1行=1注文」で、顧客名と注文金額が欲しい → 上記でOK
- 意図と違う: 「1行=1顧客」で、顧客ごとの合計が欲しい → 先に集計(GROUP BY)してから扱う
結合前後の件数確認(まずここをやる)
- 結合する各表を単体で
SELECT COUNT(*)する - 結合後の結果を
SELECT COUNT(*)する(または件数が分かる方法で確認) - 結合後が「どれかの表より明らかに多い」→ 1対多の多側を結合している、または JOIN 条件が足りていない
-- 例:顧客10件、注文50件 → JOIN後は50行が自然
SELECT COUNT(*) FROM customers; -- 10
SELECT COUNT(*) FROM orders; -- 50
SELECT COUNT(*) FROM customers c JOIN orders o ON o.customer_id = c.id; -- 50
結合後が 10 でも 50 でもなく、異常に大きい(例:500)場合は、JOIN条件の不足(同じキーで複数紐づく・条件が甘い)を疑います。
よくあるミス
- 結合後の件数を見ずに「動いた」で終わる
- 「1行=何か」を決めずにJOINする(顧客単位か注文単位かで、GROUP BY が必要かが変わる)
- 複数回JOINするときに、途中の件数を確認しない(2つ目・3つ目のJOINで一気に増えることがある)
練習問題(2問)
- 顧客と注文をJOINしたとき、結合前(顧客数・注文数)と結合後の件数を出し、関係を確認する
- 「顧客ごとに注文数が2件以上の顧客」を取りたいとき、JOINだけでは足りず GROUP
BY と HAVING が必要になる理由を、件数の観点で説明する
