SQL

【SQL】なぜデカルト積が起きたのか紐とく【SQLアンチパターン】

アンチパターンの17章でデカルト積になる理由が分からなかったので、一行ずつ実行してできるテーブルを確認していったので、それを備忘録にまとめていきたいと思います。
テーブルの構成やデータは前回の記事を見ていただけたらと思います。

一行ずつみていく

まずは元のSQL文を見てみます。

SELECT bp.product_id, count(f.bug_id) AS count_fixed, COUNT(o.bug_id) AS count_open FROM bugs_products bp 
INNER JOIN bugs f ON bp.bug_id = f.bug_id AND f.status = 'FIXED'
INNER JOIN bugs_products p2 USING (product_id)
INNER JOIN bugs o ON p2.bug_id = o. but_id AND o.status = 'OPEN'
WHERE bp.product_id = 1
GROUP BY bp.product_id;

得たい結果は次のようなテーブルとします。

product_idcount_fixedcount_open
132

ではさっそく見ていきますが、テーブルが3つ結合していてSQL初心者の自分としては訳がわからないので、一つずつ分解していきます。
まずは一番単純なものから。

SELECT * FROM bugs_products bp INNER JOIN bugs f ON bp.bug_id = f.bug_id;
bp.bug_idbp.product_idb.bug_idb.status
111FIXED
212FIXED
313OPEN
414OPEN
515FIXED
121FIXED
222FIXED

次はAND条件でステータスを絞ります。

bp.bug_idbp.product_idb.bug_idb.status
111FIXED
212FIXED
515FIXED
121FIXED
222FIXED

さらにbugs_productsテーブルを結合します。

SELECT * FROM bugs_products bp INNER JOIN bugs f ON bp.bug_id = f.bug_id AND f.status = 'FIXED' INNER JOIN bugs_products p2 USING (product_id);

product_idが1のレコードが15行、2のレコードが4行できてしまいました。この理由は図に書いたほうがわかりやすいのですが、テーブル結合の怖いところがでてますね。

これでさらに今度はOPENのものだけbagsテーブルを結合させます。

SELECT * FROM bugs_products bp INNER JOIN bugs f ON bp.bug_id = f.bug_id AND f.status = 'FIXED' inner join bugs_products p2 USING (product_id) INNER JOIN bugs o ON p2.bug_id = o.bug_id AND o.status = 'OPEN';
bp.product_idbp.bug_idb.bug_idb.statusp2.bug_idf.bug_idf.status
111FIXED33OPEN
122FIXED33OPEN
155FIXED33OPEN
111FIXED44OPEN
122FIXED44OPEN
155FIXED44OPEN

もういよいよ意図した結果にならないのが目に見えると思います。
最後にCOUNTします。

SELECT bp.product_id, COUNT(f.bug_id), COUNT(o.bug_id) FROM bugs_products bp INNER JOIN bugs f ON bp.bug_id = f.bug_id AND f.status = 'FIXED' INNER JOIN bugs_products p2 USING (product_id) INNER JOIN bugs o ON p2.bug_id = o.bug_id AND o.status = 'OPEN' WHERE bp.product_id = 1 GROUP BY bp.product_id;
product_idCOUNT(f.bug_id)COUNT(o.bug_id)
166

さいごに

パット見だと僕も最初はふつうに動くSQL文に見えましたが、SQLの怖い部分が出てました。
メンテナンスの意味でもスパゲッティクエリは書かないよう、コスト等考えてクエリを分割することを意識していきたいと思いました。

ABOUT ME
sakai
東京在住の30歳。元々は車部品メーカーで働いていてましたが、プログラミングに興味を持ちスクールに通ってエンジニアになりました。 そこからベンチャー → メガベンチャー → 個人事業主になりました。 最近は生成 AI 関連の業務を中心にやっています。 ヒカルチャンネル(Youtube)とワンピースが大好きです!