这是我的询问:
SELECT COUNT(*)
, DATE(created_ts)
FROM users
GROUP BY DATE(created_ts);
如果用户选择一个时间范围,例如
2024-12-17 00:00:00
-2024-12-17 15:59:59
2024-12-16 16:00:00
- 2024-12-17 15:59:59
SELECT COUNT(*)
, DATE(created_ts)
FROM users
WHERE NOT created_ts < '2024-12-16 16:00:00'
AND created_ts <= '2024-12-17 15:59:59'
GROUP BY DATE(created_ts);
那么执行这条sql就会生成16-17号组。 这将导致
COUNT(*)
不准确。请告诉我如何处理。
我不知道该怎么办,希望查询结果是用户想要的,仅此而已
默认情况下,
timestamp
使用微秒分辨率。将上限向下移动一秒同时使其包含在内会导致问题 - 只需对两者使用 16:00 并使用 >
使一个包含,一个使用 <=
排除(顺便说一下,您的第一个边界比较已翻转):SELECT COUNT(*)
, DATE(created_ts)
FROM users
WHERE NOT created_ts > '2024-12-16 16:00:00'
AND created_ts <= '2024-12-17 16:00:00'
GROUP BY DATE(created_ts);
否则,从
15:59:59.000001
到 15:59:59.999999
的整整一秒都不属于任何一个范围。
timestampTZ
,并让客户也向您发送 timestampTZ
,以完全消除歧义。
alter table users
alter column created_ts type timestampTZ;
它们是时区感知时间戳,成本完全相同,而常规的
timestamp
只是一张“时钟图片”,这会导致像您所面临的问题。如果您的客户已经向您发送 UTC timestampTZ
,您只需确保该列已更改,就可以了。
如果您的客户向您发送不知道时区的时区
timestamp
,但你们都同意它是 UTC,您可以使用 at time zone
应用转变并使其了解时区:
SELECT COUNT(*)
, DATE(created_ts)
FROM users
WHERE NOT created_ts > '2024-12-16 16:00:00'::timestamp at time zone 'UTC'
AND created_ts <= '2024-12-17 16:00:00'::timestamp at time zone 'UTC'
GROUP BY DATE(created_ts);
确保运行此查询的会话使用
set TimeZone='UTC';
打开会产生相同的效果 - 将 timestamptz
与 timestamp
进行比较,使得 Postgres 更喜欢将后者转换为 timestamptz
而不是丢失时区。当它将 timestamp
转换为 timestamptz
时,它假定其处于当前 TimeZone
设置指示的时区。