【问题标题】:Counting records and grouping them by the hour计数记录并按小时分组
【发布时间】:2019-06-19 21:32:27
【问题描述】:

我正在尝试计算表中的记录并按小时对它们进行分组,我的查询得到了结果,但我希望它每小时返回一次,即使没有记录。

我目前的查询是,

SELECT nvl(count(*),0) AS transactioncount, trunc(date_modified, 'HH') as TRANSACTIONDATE
FROM TABLE 
WHERE date_modified between to_date('23-JAN-19 07:00:00','dd-MON-yy hh24:mi:ss') and to_date('24-Jan-19 06:59:59','dd-MON-yy hh24:mi:ss') 
group by trunc(date_modified, 'HH');

这会返回这样的结果,

TRANSACTIONCOUNT    |    TRANSACTIONDATE
      43            |   23-Jan-19 07:00:00
      47            |   23-Jan-19 08:00:00
      156           |   23-Jan-19 14:00:00
      558           |   23-Jan-19 15:00:00

我想要的是它在我的两个日期之间每小时返回一次,

TRANSACTIONCOUNT    |    TRANSACTIONDATE
      43            |   23-Jan-19 07:00:00
      47            |   23-Jan-19 08:00:00
      0             |   23-Jan-19 09:00:00
      0             |   23-Jan-19 10:00:00
      0             |   23-Jan-19 11:00:00
      0             |   23-Jan-19 12:00:00
      0             |   23-Jan-19 13:00:00
      156           |   23-Jan-19 14:00:00
      558           |   23-Jan-19 15:00:00
  --......
      0             |   24-Jan-19 00:00:00
      0             |   24-Jan-19 01:00:00
      0             |   24-Jan-19 02:00:00
  --and so on

【问题讨论】:

    标签: sql oracle oracle11g


    【解决方案1】:

    要填补交易时间中的漏洞,您首先要创建一个完整的小时表。

    你可以使用Recursive Subquery Factoring来做

    WITH hour_table(TRANSACTIONDATE) AS (
       SELECT to_date('23-JAN-19 07:00:00','dd-MON-yy hh24:mi:ss') /* init hour here */
         FROM DUAL
      UNION ALL
       SELECT TRANSACTIONDATE + 1/24
         FROM hour_table
        WHERE TRANSACTIONDATE + 1/24 < to_date('24-JAN-19 06:59:59','dd-MON-yy hh24:mi:ss') /* limit here */
    )
    select * from hour_table;
    
    TRANSACTIONDATE   
    -------------------
    23.01.2019 07:00:00 
    23.01.2019 08:00:00 
    ... 
    24.01.2019 05:00:00 
    24.01.2019 06:00:00 
    

    请注意,您在此查询中使用了开始日期和结束日期,开始日期必须精确到一个小时。

    下一步就像外部加入这个小时表到您的聚合一样简单,并使用NVL设置缺失小时的默认值。

    with hour_table(TRANSACTIONDATE) AS (
       SELECT to_date('23-JAN-19 07:00:00','dd-MON-yy hh24:mi:ss') /* init hour here */
         FROM DUAL
      UNION ALL
       SELECT TRANSACTIONDATE + 1/24
         FROM hour_table
        WHERE TRANSACTIONDATE + 1/24 < to_date('24-JAN-19 06:59:59','dd-MON-yy hh24:mi:ss') /* limit */
    ),
    agg as (   
       SELECT nvl(count(*),0) AS transactioncount, trunc(date_modified, 'HH') as TRANSACTIONDATE
       FROM "TABLE" 
       WHERE date_modified between to_date('23-JAN-19 07:00:00','dd-MON-yy hh24:mi:ss') and to_date('24-Jan-19 06:59:59','dd-MON-yy hh24:mi:ss') 
       group by trunc(date_modified, 'HH')
    )
    select t.TRANSACTIONDATE, nvl(transactioncount,0) transactioncount
    from hour_table t
    left outer join agg a
    on t.TRANSACTIONDATE = a.TRANSACTIONDATE
    order by 1;
    

    【讨论】:

      【解决方案2】:

      您可以考虑将以下内容与CONNECT BY level 逻辑一起使用:

      SELECT sum(transactioncount) as transactioncount, transactiondate 
        FROM
        (
         with "TABLE"(date_modified) as
         (
           SELECT timestamp'2019-01-23 08:00:00' FROM dual union all
           SELECT timestamp'2019-01-23 08:30:00' FROM dual union all
           SELECT timestamp'2019-01-23 09:00:00' FROM dual union all
           SELECT timestamp'2019-01-24 05:01:00' FROM dual   
         )   
        SELECT nvl(count(*),0) AS transactioncount, trunc(date_modified, 'hh24') as transactiondate
          FROM "TABLE" t 
         GROUP BY trunc(date_modified, 'HH24')
        UNION ALL
        SELECT 0, timestamp'2019-01-23 07:00:00' + ( level - 1 )/24
          FROM dual    
       CONNECT BY level <=  24 * extract( day  from 
                                  timestamp'2019-01-24 06:59:59'-
                                  timestamp'2019-01-23 07:00:00') +
                                 extract( hour from 
                                  timestamp'2019-01-24 06:59:59'-
                                  timestamp'2019-01-23 07:00:00') + 1      
      )    
       GROUP BY transactiondate
       ORDER BY transactiondate
      

      Rextester Demo

      【讨论】:

      • mmm... 它有效,但当该小时没有数据时,它没有显示“23-JAN-19 07:00:00”。
      • @crimson589 对不起,( level - 1 ) 的窍门不见了。这样,由于级别的缺失值为零,开始时间被排除在外。
      • 抱歉,今天才来试一试。我将其更改为(级别 - 1),但现在如果没有该日期的数据,我将失去 1 月 24 日早上 6 点。
      • @crimson589 你是对的。我意识到没有考虑“一天”部分,现在补充说。 (+1) 最后的区别来自逻辑“在第 2 和第 5 之间存在四棵树,包括边界,计算为 5 - 2 + 1 = 4 including the substracted, i.e. 2nd one
      猜你喜欢
      • 2019-03-09
      • 2014-12-19
      • 1970-01-01
      • 1970-01-01
      • 2020-01-17
      • 2020-07-17
      • 2017-05-03
      • 2012-07-29
      • 1970-01-01
      相关资源
      最近更新 更多