我有一个跟踪某个资源使用情况的表。它看起来像这样:
started | timestamp with time zone | not null
last_ping | timestamp with time zone |
stopped | timestamp with time zone |
stopped
和last_ping
字段可能为空。如果它们都已填满,则stopped
是相关的。
开始和结束日期只能跨越几秒或多个日期。
我想获得过去14天的每日使用情况清单。
我知道我可以获得过去14天的清单:
SELECT day
FROM generate_series(CURRENT_DATE, CURRENT_DATE - 14, '-1 day'::interval) day;
我可以获得每个使用条目的总持续时间:
SELECT COALESCE(stopped, last_ping, started) - started AS duration
FROM api_sessionusage;
我还可以将这两个查询组合在一起,并添加一个限制,该限制仅考虑到午夜的持续时间:
SELECT
day,
(
SELECT SUM(
LEAST(COALESCE(stopped, last_ping, started), day + interval '1 day') - started
)
FROM api_sessionusage
WHERE started >= day AND started < day + interval '1 day'
) AS aggregated_duration
FROM generate_series(CURRENT_DATE, CURRENT_DATE -14, '-1 day'::interval) day;
这里的问题是,午夜后结束的使用会话仅计入开始日期,但午夜后的持续时间不会被考虑在内。
如何重写查询以便在过去14天内获得每天的汇总使用情况?
答案 0 :(得分:3)
使用overlap and intersect operators时间戳范围类型:
select
day,
sum(upper(daily_range) - lower(daily_range))
from (
select
day,
session_range * tstzrange(day, day::date + 1) daily_range
from generate_series(current_date, current_date -14, '-1 day'::interval) day
left join (
select tstzrange(started, coalesce(stopped, last_ping, started)) session_range
from api_sessionusage
) s
on session_range && tstzrange(day, day::date + 1)
) s
group by 1
order by 1;
注意:
coalesce(stopped, last_ping, started) - started as duration
如果stopped
和last_ping
都为空,则为零。也许它应该是
coalesce(stopped, last_ping, current_date) --?