【问题标题】:Select data grouped by time over midnight选择按午夜时间分组的数据
【发布时间】:2015-09-24 23:35:00
【问题描述】:

我有一张这样的桌子:

ID       TIMEVALUE
-----    -------------
1        06.07.15 06:43:01,000000000
2        06.07.15 12:17:01,000000000
3        06.07.15 18:21:01,000000000
4        06.07.15 23:56:01,000000000
5        07.07.15 04:11:01,000000000
6        07.07.15 10:47:01,000000000
7        07.07.15 12:32:01,000000000
8        07.07.15 14:47:01,000000000

我想按特殊时间对这些数据进行分组。
我当前的查询如下所示:

SELECT TO_CHAR(TIMEVALUE, 'YYYY\MM\DD'), COUNT(ID), 
  SUM(CASE WHEN TO_CHAR(TIMEVALUE, 'HH24MI') <=700 THEN 1 ELSE 0 END) as morning,
  SUM(CASE WHEN TO_CHAR(TIMEVALUE, 'HH24MI') >700 AND TO_CHAR(TIMEVALUE, 'HH24MI') <1400 THEN 1 ELSE 0 END) as daytime,
  SUM(CASE WHEN TO_CHAR(TIMEVALUE, 'HH24MI') >=1400 THEN 1 ELSE 0 END) as evening FROM Table
WHERE TIMEVALUE >= to_timestamp('05.07.2015','DD.MM.YYYY')
GROUP BY TO_CHAR(TIMEVALUE, 'YYYY\MM\DD')

我得到了这个输出

day          overall     morning    daytime    evening 
-----        ---------
2015\07\05   454         0          0          454
2015\07\06   599         113        250        236
2015\07\07   404         139        265        0

所以在同一天分组(0-7 点、7-14 点和 14-24 点)
但我现在的问题是: 如何在午夜进行分组?

例如从第二天的 6-14、14-23 和 23-6 点开始计数。

希望你能理解我的问题。如果有更好的解决方案,欢迎您甚至改进我的上层查询。

【问题讨论】:

  • 将 GROUP BY TO_CHAR(TIMEVALUE, 'YYYY\MM\DD') 调整为例如 1 小时。
  • 你的意思是像GROUP BY TO_CHAR(TIMEVALUE-(6/24), 'YYYY\MM\DD HH24')这样的东西?太好了,我去测试一下

标签: sql oracle group-by


【解决方案1】:

编辑:现在测试:SQL Fiddle

关键是简单地调整group by,以便早上 6 点之前的任何内容都与前一天分组。在那之后,计数就很简单了。

SELECT TO_CHAR(CASE WHEN EXTRACT(HOUR FROM timevalue) < 6
                    THEN timevalue - 1
                    ELSE timevalue
                    END, 'YYYY\MM\DD') AS day, 
       COUNT(*) AS overall, 
       SUM(CASE WHEN EXTRACT(HOUR FROM timevalue) >= 6 AND EXTRACT(HOUR FROM timevalue) < 14
                THEN 1 ELSE 0 END) AS morning,
       SUM(CASE WHEN EXTRACT(HOUR FROM timevalue) >= 14 AND EXTRACT(HOUR FROM timevalue) < 23
                THEN 1 ELSE 0 END) AS daytime,
       SUM(CASE WHEN EXTRACT(HOUR FROM timevalue) < 6 OR EXTRACT(HOUR FROM timevalue) >= 23
                THEN 1 ELSE 0 END) AS evening
FROM my_table
WHERE timevalue >= TO_TIMESTAMP('05.07.2015','DD.MM.YYYY')
GROUP BY TO_CHAR(CASE WHEN EXTRACT(HOUR FROM timevalue) < 6
                    THEN timevalue - 1
                    ELSE timevalue
                    END, 'YYYY\MM\DD');

【讨论】:

    【解决方案2】:

    从 timevalue 中减去 1 天,首先是低于 '06:00' 的时间,然后:

    SQLFiddle demo

    select TO_CHAR(day, 'YYYY\MM\DD') day, COUNT(ID) cnt, 
        SUM(case when '23' < tvh or  tvh <= '06' THEN 1 ELSE 0 END) as midnight,
        SUM(case when '06' < tvh and tvh <= '14' THEN 1 ELSE 0 END) as daytime,
        SUM(case when '14' < tvh and tvh <= '23' THEN 1 ELSE 0 END) as evening
      FROM (
        select id, to_char(TIMEVALUE, 'HH24') tvh,
            trunc(case when (to_char(timevalue, 'hh24') <= '06') 
                       then timevalue - interval '1' day  
                       else timevalue end) day
          from t1
        )
      GROUP BY day
    

    【讨论】:

      【解决方案3】:

      也许你可以这样做(通过一些重新格式化或 PIVOT):

      WITH spans AS 
          (SELECT TIMESTAMP '2015-01-01 00:00:00' + LEVEL * INTERVAL '1' HOUR AS start_time
          FROM dual
          CONNECT BY TIMESTAMP '2015-01-01 00:00:00' + LEVEL * INTERVAL '1' HOUR < LOCALTIMESTAMP),
      t AS 
          (SELECT start_time, lead(start_time, 1) OVER (ORDER BY start_time) AS end_time, ROWNUM AS N
          FROM spans
          WHERE EXTRACT(HOUR FROM start_time) IN (6,14,23))
      SELECT N, start_time, end_time, COUNT(*) AS ID_COUNT,
          DECODE(EXTRACT(HOUR FROM start_time), 6,'morning', 14,'daytime', 23,'evening') AS daytime
      FROM t
          JOIN YOUR_TABLE WHERE TIMEVALUE BETWEEN start_time AND end_time
      GROUP BY N;
      

      当然,初始时间值(在我的示例中为“2015-01-01 00:00:00”)必须小于表中的最小日期。

      【讨论】:

        猜你喜欢
        • 2016-07-28
        • 1970-01-01
        • 1970-01-01
        • 2012-03-31
        • 2015-08-22
        • 2012-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多