两个表中都有计数的Mysql内部联接
我有一个products表和一个changelog表。products表有各种类别(Cat 1、Cat 2、Cat3)和价格级别(Level1、Level2、Level3),我想对它们进行计数、分组和排序。所以我有两个表中都有计数的Mysql内部联接,mysql,Mysql,我有一个products表和一个changelog表。products表有各种类别(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_lev
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),它有一个productId字段,链接到products.id字段。它还有一个“状态”字段,其值为Active(活动)、Inactive(不活动)。因此,我想将status字段添加到显示有效产品的表中,如下所示:
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
计数失控,因为似乎changelog表中的每个条目的类别计数都在累积。此查询有什么问题?必须在包含多个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
您可以为此使用相关子查询:
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'
记录的计数。因为表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(…)
:它利用布尔表达式的计算结果为0或1的事实;在我看来,它更清晰,也更短李>COUNT(在…结束时的情况)
而不是按计数排序(id)
:在分组依据的字段上应用聚合是很奇怪的。虽然在MySql中有效,但在标准SQL中它是不允许的。也没有必要,;我发现计数按计数排序(类别)
出现次数更具可读性,即使它有相同的结果id
- 我没有使用
子句来过滤活动的变更日志记录,因为通过CASE WHEN
子句过滤这些记录更有效WHERE