2013-04-25 95 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

相关问题