我具有以下(简化)结构的登录表:
id | login_time
---------
1 | 2019-02-04 18:14:30.026361+00
2 | 2019-02-04 22:10:19.720065+00
3 | 2019-02-06 15:51:53.799014+00
现在我要生成这样的图表:
基本上我想显示过去48小时内的登录信息。
我当前的查询:
SELECT count(*), date_trunc('hour', login_time) as time_trunced FROM user_logins
WHERE login_time > now() - interval '48' hour
GROUP BY time_trunced
ORDER BY time_trunced DESC
只要每个小时都有条目,此方法就起作用。但是,如果在某个小时内没有登录,则不会选择任何条目,例如:
time_trunced | count
---------------------
12:00 | 1
13:00 | 2
15:00 | 3
16:00 | 5
我需要一个连续查询,以便可以将计数值简单地放入数组中:
time_trunced | count
---------------------
12:00 | 1
13:00 | 2
14:00 | 0 <-- This is missing
15:00 | 3
16:00 | 5
基于此,我可以简单地将查询结果转换为[1, 2, 0, 3, 5]
之类的数组,并将其传递给我的前端。
postgresql是否可能?还是我需要实现自己的逻辑?
答案 0 :(得分:2)
我想我会这样做:
select gs.h, count(ul.login_time)
from generate_series(date_trunc('hour', now() - interval '48 hour', date_trunc('hour', now()), interval '1 hour'
) gs(h) left join
user_logins ul
on ul.login_time >= gs.h and
ul.login_time < gs.h + interval '1 hour'
group by gs.h
order by gs.h;
答案 1 :(得分:1)
几乎可以肯定地将其整理一下,但应该给您一些帮助。为generate_series()
提示提供clamp的建议:
SELECT t.time_trunced,coalesce(l.login_count,0) as logins
FROM
(
-- Generate an inline view with all hours between the min & max values in user_logins table
SELECT date_trunc('hour',a.min_time)+ interval '1h' * b.hr_offset as time_trunced
FROM (select min(login_time) as min_time from user_logins) a
JOIN (select generate_series(0,(select ceil((EXTRACT(EPOCH FROM max(login_time))-EXTRACT(EPOCH FROM min(login_time)))/3600) from user_logins)::int) as hr_offset) b on true
) t
LEFT JOIN
(
-- OP's original query tweaked a bit
SELECT count(*) as login_count, date_trunc('hour', login_time) as time_trunced
FROM user_logins
GROUP BY time_trunced
) l on t.time_trunced=l.time_trunced
order BY 1 desc;