結合するテーブルがある場合genre
、「明白な」解決策は次のようになります。
SELECT genre.id AS genre, COUNT(products.id) AS n
FROM genre
LEFT JOIN products ON genre.id IN (genre_id, genre_id2)
GROUP BY genre.id
( SQLFiddle デモ)
ただし、そうしなかった場合でも、次を使用してこれを行うことができますUNION
。
SELECT genre, COUNT(*) as n
FROM
(SELECT id, genre_id AS genre FROM products
WHERE genre_id IS NOT NULL
UNION
SELECT id, genre_id2 AS genre FROM products
WHERE genre_id2 IS NOT NULL) AS foo
GROUP BY genre
( SQLFiddle デモ)
編集:このメソッドは、カウントが 0 の行を返しませUNION
ん (そしてできませんLEFT JOIN
) 。それらが必要ない場合は、LEFT JOIN
を単にJOIN
.
編集 2:適切なインデックス ( と のそれぞれに 1 つgenre_id
)genre_id2
を使用し、実際のデータ セットのサイズと内容に応じて、従属サブクエリを使用する次のソリューションは、上記のいずれよりも効率的である可能性があります。
SELECT genre.id AS genre,
(SELECT COUNT(*) FROM products WHERE genre.id = genre_id) +
(SELECT COUNT(*) FROM products WHERE genre.id = genre_id2) AS n
FROM genre
カウントがゼロの行を削除するには、そのまま貼り付けます
HAVING n > 0
クエリの最後に。( SQLFiddle デモ) これは、実際には、そのような行を除外するための一般的な方法です。
実際のデータが必要になるため、どちらがより効率的であるかを確認するために、JWのソリューションに対してこれをベンチマークしていません。データセットがかなり小さい場合は、どちらの方法でも問題ない場合があります。
(結果は、MySQL がそれらをどれだけうまく最適化するかに大きく依存します。JW のネストされたLEFT JOIN
s は、単純に実行すると、大きなデータ セットで非常に遅くなる可能性がありますが、MySQL がそれを行わないほどスマートであるかどうかはわかりません。その間、私の従属サブクエリおそらくあまり最適化されませんが、必要なインデックスが存在する限り、単純な実行でもかなり高速になるはずです。)
編集 3:一般に、この問題はテーブルの設計が悪いために発生することに注意してください。この回答などで説明されているように、ジャンクション テーブルを使用するようにスキーマを変更することをお勧めします。
これにより、各製品を任意の数のジャンルに属することができ、次のような単純なクエリを使用して各ジャンルの製品を簡単に数えることができます。
SELECT genre.id AS genre, COUNT(products.id) AS n
FROM genre
JOIN product_genre ON genre.id = product_genre.genre
JOIN products ON product.id = product_genre.product
GROUP BY genre.id