汇总案例陈述中的总数与计数之差

问题描述

我在下面有一个查询

    SELECT 
       d.name,SUM(CASE WHEN e.salary > 100000 THEN 1 ELSE 0 END)
        / COUNT(disTINCT e.id)
        AS pct_above_100k,COUNT(disTINCT e.id) AS c
FROM employees e JOIN departments d ON e.department_id = d.id
GROUP BY 1
HAVING COUNT(*) > 10
ORDER BY 2 DESC

我@R_404_6329@使用sum,但是如果我使用count会有所不同吗?

我知道count是对一个值存在的次数进行计数,并且sum将实际值相加,但是@R_404_6329@,由于我的条件是如果薪水> 100000,它将始终视为1吗?

谢谢!

解决方法

我们使用filter子句有条件地进行计数:

COUNT(*) FILTER (WHERE e.salary > 100000)

其他一些dBMS不支持filter子句。在这里,我们通过使用CASE WHEN自己评估表达式来使用变通方法,并使用COUNTSUM来添加匹配项。这里有一些方法可以做到这一点:

SUM(CASE WHEN e.salary > 100000 THEN 1 ELSE 0 END)
COUNT(CASE WHEN e.salary > 100000 THEN 1 ELSE NULL END)
COUNT(CASE WHEN e.salary > 100000 THEN 1 END)
COUNT(CASE WHEN e.salary > 100000 THEN 'count this' END)

因为PostgreSQL确实支持filter子句,所以您应该使用COUNT(*) FILTER (...)

,

如果仅将sum替换为count,则会得到不同的结果,因为0等于1。

最优雅的写法是FILTER子句,就像其他人提到的那样,但是您也可以这样做:

count(CASE WHEN e.salary > 100000 THEN 0 END)

这将起作用,因为(大多数)聚合函数将忽略NULL值。

,

假定员工不在多个部门中,所以count(distinct)是不必要的。

这意味着代码可以更简单地写为:

  AVG(CASE WHEN e.salary > 100000 THEN 1 ELSE 0 END) AS pct_above_100k,

或者:

  AVG( (e.salary > 100000)::int ) AS pct_above_100k,

这些方法比其他方法更有效,因为COUNT(DISTINCT)通常比其他聚合函数贵一些。