Mysql内连接与两个表中的计数

时间:2016-03-07 20:43:03

标签: mysql

我有一个产品表和一个更改日志表。产品表有各种类别(Cat 1,Cat 2,Cat3)和价格水平(Level1,Level2,Level3),我想计算和分类。所以我有

SELECT products.category,
COUNT(CASE WHEN products.price_level='1' THEN products.category END) as 'Level1',
COUNT(CASE WHEN products.price_level='2' THEN products.category END) as 'Level2',
COUNT(CASE WHEN products.price_level='3' THEN products.category END) as 'Level3'
FROM products
GROUP BY products.category
ORDER BY COUNT(products.category) DESC

结果是:

Category  Level1   Level2   Level3
Cat1       33       14        6
Cat2       19       29        10
Cat3       5        17       15

到目前为止,非常好......这很好。

现在我想在(changelog)中带另一个表,该表有一个链接到products.id字段的productId字段。它还具有字段状态'值为Active,Inactive)。所以我想将状态字段添加到显示有效产品的表中,如下所示:

Category  Level1   Level2   Level3  Active
Cat1       33       14        6
Cat2       19       29       10
Cat3       5        17       15

所以我做了这个不起作用:

SELECT products.category,
COUNT(CASE WHEN products.price_level='1' THEN products.category END) as 'Level1',
COUNT(CASE WHEN products.price_level='2' THEN products.category END) as 'Level2',
COUNT(CASE WHEN products.price_level='3' THEN products.category END) as 'Level3',
COUNT(CASE WHEN changelog.status='Active' THEN changelog.status END) as 'Active'

FROM products

LEFT JOIN changelog on products.id=changelog.productId

GROUP BY products.category
ORDER BY COUNT(products.category) DESC

计数变得混乱,因为看起来类别计数可能正在为更改日志表中的每个条目累积。这个查询出了什么问题?

3 个答案:

答案 0 :(得分:1)

您可以使用相关的子查询:

SELECT t.category,
       COUNT(CASE WHEN t.price_level='1' THEN t.category END) as 'Level1',
       COUNT(CASE WHEN t.price_level='2' THEN t.category END) as 'Level2',
       COUNT(CASE WHEN t.price_level='3' THEN t.category END) as 'Level3',
       (SELECT COUNT(CASE 
                      WHEN c.status='Active' THEN c.status 
                    END) 
       FROM changelog AS c
       INNER JOIN products AS p ON p.id=c.productId
       WHERE p.category = t.category) AS  'Active' 
FROM products AS t       
GROUP BY t.category
ORDER BY COUNT(t.category) DESC

子查询返回与当前产品类别相关的'Active'条记录数。

答案 1 :(得分:0)

您必须在包含超过1-1关系的连接之前实现计数。

SELECT P.category, P.level1, p.level2, p.level3,
COUNT(CASE WHEN changelog.status='Active' THEN changelog.status END) as 'Active'
FROM (SELECT category, ID
      COUNT(CASE WHEN price_level='1' THEN category END) as 'Level1',
      COUNT(CASE WHEN price_level='2' THEN category END) as 'Level2',
      COUNT(CASE WHEN price_level='3' THEN category END) as 'Level3'
      FROM products
       GROUP BY category, ID) P
LEFT JOIN changelog 
   on p.id=changelog.productId
ORDER BY COUNT(p.category) DESC

答案 2 :(得分:0)

因为表 changelog 每个产品可以有多个记录,所以它会增加您已有的计数。

解决此问题的一种方法是,通过计算子查询中 changelog 表中的活动记录,然后将其连接到查询的其余部分:

SELECT    p.category,
          SUM(p.price_level='1') as 'Level1',
          SUM(p.price_level='2') as 'Level2',
          SUM(p.price_level='3') as 'Level3',
          COALESCE(c.cnt, 0)     as 'Active'
FROM      products AS p
LEFT JOIN (
           SELECT   productId, 
                    COUNT(*) as cnt 
           FROM     changelog
           WHERE    status = 'Active'
           GROUP BY productId
          ) AS c
       ON c.productId = p.id
GROUP BY  p.category
ORDER BY  COUNT(p.id) DESC

我还做了两个其他的改变:

  • SUM(......)而不是COUNT(CASE WHEN...END):它利用布尔表达式求值为0或1的事实;在我看来,它更清楚,也更短;
  • ORDER BY COUNT(id)而不是ORDER BY COUNT(category):在您分组的字段上应用聚合是很奇怪的。虽然在MySql中有效,但在标准SQL中它是不允许的。这也没有必要;我发现计算id次出现的可读性更高,即使它具有相同的结果。
  • 我没有使用CASE WHEN子句来过滤活动的更改日志记录,因为通过WHERE子句过滤这些记录会更有效。