如何统计 payment_date 为星期一的付款数量?
支付老李
结论
TO_CHAR(payment_date, 'Day') 会把星期名称填充到固定宽度。星期一通常会返回 'Monday ',所以无法与 'Monday' 精确匹配。
建议改用 ISO 星期编号:
SELECT COUNT(*)
FROM payment
WHERE EXTRACT(ISODOW FROM payment_date) = 1;
在 PostgreSQL 中,EXTRACT(ISODOW ...) 返回 1 到 7。1 表示星期一,7 表示星期日。
原查询为什么返回 0
TO_CHAR 的 Day 格式会在结果右侧补空格。例如:
SELECT '[' || TO_CHAR(DATE '2026-08-24', 'Day') || ']';
结果可能是:
[Monday ]
因此,下面的条件不成立:
TO_CHAR(payment_date, 'Day') = 'Monday'
星期名称还会受到数据库会话区域设置的影响。在非英语环境中,Day 不一定返回英文的 Monday,所以用星期名称过滤并不可靠。
推荐解决方案
直接按 ISO 星期编号统计:
SELECT COUNT(*)
FROM payment
WHERE EXTRACT(ISODOW FROM payment_date) = 1;
无论 payment_date 是 date、timestamp 还是 timestamptz 类型,都可以使用这种写法。
保留 TO_CHAR 时的修正方法
可以添加 FM 格式修饰符,取消右侧填充:
SELECT COUNT(*)
FROM payment
WHERE TO_CHAR(payment_date, 'FMDay') = 'Monday';
也可以明确去掉空格:
SELECT COUNT(*)
FROM payment
WHERE TRIM(TO_CHAR(payment_date, 'Day')) = 'Monday';
不过,这两种写法仍然依赖星期名称和区域设置,通常没有 EXTRACT(ISODOW ...) 稳定。
注意事项
如果 payment_date 是 timestamptz,星期几会按当前会话时区计算。同一笔付款在不同时区可能属于不同日期。如果需要按指定的业务时区统计,应先转换时区,例如:
SELECT COUNT(*)
FROM payment
WHERE EXTRACT(
ISODOW FROM payment_date AT TIME ZONE 'Asia/Shanghai'
) = 1;
请将时区名称替换为业务实际使用的时区。payment_date 为 NULL 的记录不满足筛选条件,也不会计入结果。
备注:内容仅供参考。
