【问题标题】:sql script to group hourly using datepart and fill the empty with 0sql脚本使用datepart每小时分组并用0填充空
【发布时间】:2021-10-20 19:51:04
【问题描述】:

此脚本给出表中时间戳的每小时计数。

SELECT date_trunc('hour', s.fill_instant) h , count(date_trunc('hour', s.fill_instant)) c FROM sms s
left join station s2 on
s.station_id = s2.station_id
where
s2.address like '%arizona%' and s.fill_date between '2021-09-19' and '2021-09-19'
GROUP BY date_trunc('hour', s.fill_instant)
order by date_trunc('hour', s.fill_instant) asc;

如下表所示

2021-09-19 00:00:00 3
2021-09-19 02:00:00 20
2021-09-19 03:00:00 6
2021-09-19 13:00:00 7
2021-09-19 14:00:00 11
2021-09-19 15:00:00 6

如何在非当前时间插入零。所以它显示了完整的 24 小时地图。很像这样

2021-09-19 00:00:00 3
2021-09-19 01:00:00 0
2021-09-19 02:00:00 20
2021-09-19 03:00:00 6
2021-09-19 04:00:00 0
2021-09-19 05:00:00 0
2021-09-19 06:00:00 0
2021-09-19 07:00:00 0
2021-09-19 08:00:00 0
2021-09-19 09:00:00 0
2021-09-19 10:00:00 0
2021-09-19 11:00:00 0
2021-09-19 12:00:00 0
2021-09-19 13:00:00 7
2021-09-19 14:00:00 11
2021-09-19 15:00:00 6
2021-09-19 16:00:00 0
2021-09-19 17:00:00 0
2021-09-19 18:00:00 0
2021-09-19 19:00:00 0
2021-09-19 20:00:00 0
2021-09-19 21:00:00 0
2021-09-19 22:00:00 0
2021-09-19 23:00:00 0
2021-09-19 24:00:00 0

【问题讨论】:

    标签: sql postgresql datepart


    【解决方案1】:

    使用generate_series 获取给定日期的所有小时作为CTE,然后使用left join 查询它:

    WITH hours as (Select * from generate_series('2021-09-19 00:00:00'::timestamp, '2021-09-19 23:59:59'::timestamp, INTERVAL '1 hour') as hr)
    SELECT hours.hr, coalesce(qry.c, 0) as c
    FROM hours 
    LEFT JOIN(SELECT date_trunc('hour', s.fill_instant) h , count(date_trunc('hour', s.fill_instant)) c FROM sms s
    left join station s2 on s.station_id = s2.station_id
    where
    s2.address like '%arizona%' and s.fill_date between '2021-09-19' and '2021-09-19'
    GROUP BY date_trunc('hour', s.fill_instant)
    order by date_trunc('hour', s.fill_instant) asc) qry on qry.h = hours.hr
    

    【讨论】:

    • 这个运行没有 JPA 环境原生查询的问题
    【解决方案2】:

    在序列中填补空白的或多或少的通用模式是这样的:
    使用您现有的查询 (t) 并将其与密集的小时序列 (ds) 外连接。使用coalescet.cnull值设置为0。

    with t as 
    (
     .. your query here .. 
    )
    select ds.h, coalesce(t.c, 0) c
    from generate_series
    (
      timestamp '2021-09-19T00:00:00', 
      timestamp '2021-09-19T24:00:00', 
      interval '1 hour'
    ) as ds(h)  
    left outer join t on t.h = ds.h;
    

    【讨论】:

    • 有没有办法让它动态意味着目标是在 JPA 中编写这个查询。我们可以用变量替换时间戳'yyyy-mm-ddTHH:MM:ss'吗
    • 肯定有 - 通过用参数替换 yyyy-mm-ddTHH:MM:ss 文字常量。 this SO 线程和here 中的一些细节。
    【解决方案3】:

    另一种生成一天中所有时间的方法是使用递归查询。

    然后您必须在hours 子查询和您的查询之间创建一个LEFT JOIN,并且在那些与您的查询不匹配的行中(c 列为空),您必须输入一个零(我使用了CASE 声明)。

    WITH RECURSIVE hours AS (SELECT '2021-09-19 00:00:00'::timestamp AS hour
                             
                             UNION ALL
                             
                             SELECT hour + interval '1 hour'
                             FROM hours
                             WHERE hour < '2021-09-19 23:00:00')
                             
    SELECT hours.hour, CASE WHEN sq.c IS NULL THEN 0 ELSE sq.c END AS c
    FROM hours
    LEFT JOIN (SELECT date_trunc('hour', s.fill_instant) h, count(date_trunc('hour', s.fill_instant)) c 
               FROM sms s
               LEFT JOIN station s2 ON s.station_id = s2.station_id
               WHERE s2.address like '%arizona%' AND s.fill_date = '2021-09-19'
               GROUP BY date_trunc('hour', s.fill_instant)) AS sq ON hours.hour = sq.h
    ORDER BY hours.hour;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-18
      • 2011-06-07
      • 1970-01-01
      相关资源
      最近更新 更多