PostgreSQL中按日期分组计算col_a为空行占比的查询修正求助
PostgreSQL中按日期分组计算col_a为空行占比的查询修正求助
嗨,我来帮你搞定这个占比计算的问题!先理清楚你的需求:你需要把col_b按日期分组,统计每天里col_a为空的行占当天总行数的百分比,对吧?
先看看你提供的示例数据:
| col_a | col_b |
|---|---|
| A | 2025-04-28 16:23:55.961 -0400 |
| 2024-03-27 17:17:08.100 -0400 | |
| C | 2024-03-27 18:57:23.194 -0500 |
| B | 2025-04-28 17:44:51.647 -0500 |
| 2023-04-28 10:47:30.667 -0400 |
你期望的结果是按日期分组,得到空值占比:
| b_date | percentage |
|---|---|
| 2023-04-28 | 66 |
| 2024-03-27 | 50 |
接下来说说你原来的查询哪里出问题了:
count(col_a=null)这部分写法不对,因为col_a=null在PostgreSQL里会返回布尔值(true/false),而count()函数会把所有非空的布尔值都算入计数,不管是true还是false,这就导致你统计的空值数量完全错误。
给你修正后的查询,有两种写法都能实现需求:
方法一:使用FILTER子句(PostgreSQL 9.4+支持,语法更清晰)
SELECT col_b::date AS b_date, ROUND( (COUNT(*) FILTER (WHERE col_a IS NULL) * 100.0) / COUNT(*), 0 -- 这里的0是保留0位小数,和你示例的整数结果对应,需要小数可调整 ) AS percentage FROM my_table GROUP BY b_date ORDER BY b_date ASC;
方法二:使用CASE表达式(兼容性更好)
SELECT col_b::date AS b_date, ROUND( (SUM(CASE WHEN col_a IS NULL THEN 1 ELSE 0 END) * 100.0) / COUNT(*), 0 ) AS percentage FROM my_table GROUP BY b_date ORDER BY b_date ASC;
为什么这么改?
- 用
COUNT(*) FILTER (WHERE col_a IS NULL)或者SUM(CASE...)可以准确统计出当天col_a为空的行数 - 乘以
100.0而不是100是为了避免整数除法(PostgreSQL里整数相除会直接取整,比如5/2会得到2而不是2.5) ROUND(..., 0)是为了把结果转成整数,和你示例里的66、50对应,如果需要保留小数可以调整这个参数
另外补充:如果只想保留有非零占比的日期,可以在GROUP BY后面加上HAVING COUNT(*) FILTER (WHERE col_a IS NULL) > 0,这样2025-04-28这种占比为0的日期就不会出现在结果里了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

