PAYATHON 2026

如何统计 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 的记录不满足筛选条件,也不会计入结果。

备注:内容仅供参考。