这是获取指定结果集的一种方法:
SELECT d.rid AS `rid`
, SUM(n.eid<=>21) AS `21`
, SUM(n.eid<=>22) AS `22`
, SUM(n.eid<=>23) AS `23`
, SUM(n.eid<=>33) AS `33`
, SUM(n.eid<=>34) AS `34`
, SUM(n.eid<=>35) AS `35`
, SUM(n.eid<=>36) AS `36`
, SUM(n.eid<=>41) AS `41`
, SUM(n.eid<=>42) AS `42`
, d.vs AS `vs`
, d.isN AS `isN`
FROM ( SELECT %d AS rid, %d AS vs, 1 AS isN ) d
LEFT
JOIN notification n
ON n.rid = d.rid
AND n.vs = d.vs
AND n.isN = d.isN
GROUP
BY d.rid
, d.vs
, d.isN
注意:表达式(n.eid<=>21)
是 的简写IF(n.eid=21,1,0)
,或者更符合 ANSI 标准CASE WHEN n.eid = 21 THEN 1 ELSE 0 END
。这给出了 0 或 1,然后可以将其与SUM
函数聚合。
您可以使用以下任何形式获得等效结果:
, SUM(n.eid<=>21) AS `21`
, COUNT(IF(n.eid=22,1,NULL)) AS `22`
, SUM(IF(n.eid=23,1,0)) AS `23`
, COUNT(CASE WHEN n.eid = 33 THEN 1 END) AS `33`
, SUM(CASE WHEN n.eid = 34 THEN 1 ELSE 0 END) AS `34`
我们在这里使用的“技巧”是我们保证别名为 as 的内联视图d
将返回一行。然后我们使用 LEFT JOIN 运算符从notification
表中提取所有“匹配”的行。这GROUP BY
将强制所有这些行被折叠(聚合)回单行。我们正在对每一行使用条件测试来查看它是否包含在给定的计数中,“技巧”是为每一行返回一个 0 或 1,然后将所有 0 和1s 进行计数。
注意:如果您使用COUNT(expr)
聚合,您希望expr
当该行包含在计数中时返回非 NULL,并且当该行不包含在计数中时返回 NULL。
如果您使用 a SUM(expr)
,那么您希望expr
在该行包含在计数中时返回 1,而在不包含时返回 0。(我们想要一个 0 而不是 NULL,这样我们就可以保证SUM(expr)
在没有要包含的行时返回“零计数”(即 0 而不是 NULL)。(当然,我们可以使用IFNULL
函数用 0 替换 NULL,但在这种情况下,它很简单,无需这样做。)
请注意,这种“计数”方法的一个优点是它可以轻松扩展以获得“组合”计数,或者在几个不同的计数中包含一行。例如
, SUM(IF(n.eid IN (41,42),1,0)) AS `total_41_and_42`
将使我们得到 eid=41 和 eid=42 行的总数。(这不是一个很好的例子,因为我们可以通过将两个计数相加来轻松地在客户端计算它。但是如果您进行更精细的计数,并且想要将单行计数为多个,这确实会成为一个优势列 ...
, SUM(IF(n.eid=42,1,0)) AS eid_42
, SUM(IF(n.eid=42 AND foo=1,1,0) AS eid_42_foo_1
, SUM(IF(n.eid=42 AND foo=2,1,0)) AS eid_42_foo_2
我们只需“一次通过”notification
表格即可获得所有这些单独的计数。如果我们尝试在 WHERE 子句中进行这些检查,我们可能需要多次通过表。