2013-04-25 101 views
2

我有2個表格,產品和流派.. 在產品表中它包含兩種流派(genre_id和genre_id2)的所有信息,只有第一個一個是必需的,所以第二個可能有NULL值MySql同一表的兩個不同列的不同值

在流派表我都用一個ID可能的流派名稱涉及到產品表的類型ID的

 
TABLE PRODUCTS 
-------------- 
id product_name genre_id  genre_id2 
------------------------------------------------- 
1  product    1    2 
2  product2   2 
3  product3   1    4 
4  product4   3    4 

TABLE GENRE 
----------- 
id genre_name 
------------------------------------------------- 
1  genre1 
2  genre2 
3  genre3 
4  genre4 

我想選擇

所有不同的流派,看看我有多少種類的產品

像這樣

 
RESULT 
------ 
genre_id  count 
----------------------- 
    1   2 
    2   2 
    3   1 
    4   2 

我有這樣的說法

SELECT DISTINCT p.genre_id AS genre, g.genre_name, COUNT(p.genre_id) AS cnt 
FROM products AS p 
JOIN genre AS g 
ON p.genre_id=g.id 
GROUP BY genre_id 
ORDER BY cnt DESC 

但只適用於genre_id,我不知道如何將genre_id2的這一說法,並補充說,與genre_id一致計數,並列出不同的人

回答

3
SELECT a.ID, COUNT(DISTINCT b.ID) + COUNT(DISTINCT c.ID) 
FROM Genre a 
     LEFT JOIN products b 
      ON a.ID = b.genre_id 
     LEFT JOIN products c 
      ON a.ID = c.genre_id2 
GROUP BY a.ID 

警告:如果您有相同genre_id and genre_ID2

5  product5   1   1 
+0

這是幾乎所有的即時尋找,但是這會把我所有的流派都拋到腦後,即使我沒有計數,可以說我是否在類型表中使用了一個類型爲5的類型5,但是我沒有任何類型爲5的產品,我該如何改變該聲明只包括流派編號的重要性? – kastulo 2013-04-25 00:41:19

+0

只需添加'HAVING COUNT(DISTINCT b.ID)+ COUNT(DISTINCT c.ID)> 0'這裏的演示http://www.sqlfiddle.com/#!2/a414e/2 – 2013-04-25 00:46:10

+0

非常感謝!我從來沒有用過HAVING,它非常方便,再次感謝,非常好的結果... – kastulo 2013-04-25 00:49:31

1

寫入記錄與genre_id2了類似的聲明,並做了一個聯盟與原結果

+0

也許你可以包括一個例子? – slm 2013-04-25 00:36:14

2

鑑於這是行不通的你有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 demo

如果你沒有,但是,你仍然可以做到這一點使用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 demo


編輯:UNION方法深得」 t(並且不能)返回任何計數爲0的行。「顯而易見」的方法會這樣做,因爲我使用了LEFT JOIN。如果你不想想要他們,你可以通過用JOIN代替LEFT JOIN來從「明顯」的方法中消除它們。


編輯2:隨着相應的索引(一個在每個genre_idgenre_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 demo)這實際上是用於濾除這些行的通用方法。

我沒有把它與JW's solution做比較,看看哪一個更有效率,因爲那需要一些實際的數據。如果你的數據集相當小,這可能無關緊要。 (結果將很大程度上取決於MySQL如何優化它們:JW的嵌套的LEFT JOIN如果天真地執行,可能會在大型數據集上變得非常緩慢,但是我不確定MySQL是否足夠聰明,不會這樣做。同時,我的依賴子查詢可能不會得到太多的優化,但即使是天真的執行應該是相當快的,只要必要的指標是有)


編輯3:需要注意的是,在一般情況下,這個問題來自壞桌子的設計。如例如所描述的,將模式改爲使用junction table會更好。在this answer

這將讓你有每個產品屬於任何數量的流派,並將讓你使用容易計算產品在每個流派一個簡單的查詢是這樣的:

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 
+0

謝謝,很好的答案,你的答案都很好。 – kastulo 2013-04-25 00:50:21

相關問題