GROUP BY时间为24小时制

时间:2011-08-01 17:03:49

标签: sql

给出以下声明,其中在表DATA中的给定时间(TIME)为用户(USER)注册任意事件:

CREATE TABLE DATA
(
  "USER" Varchar(20),
  "TIME" Time
);


INSERT INTO DATA ("USER", "TIME") VALUES ('Martin', '14:58:00.000');
INSERT INTO DATA ("USER", "TIME") VALUES ('Martin', '15:02:11.000');
INSERT INTO DATA ("USER", "TIME") VALUES ('Martin', '15:48:44.000');
INSERT INTO DATA ("USER", "TIME") VALUES ('Marion', '08:45:01.000');
INSERT INTO DATA ("USER", "TIME") VALUES ('Marion', '15:01:01.000');
INSERT INTO DATA ("USER", "TIME") VALUES ('Marion', '15:03:48.000');

在给定的一小时内找到每个用户的事件数量是微不足道的:

select 
    "USER", 
    extract(hour from "TIME") as "Hour",
    count(*)
from 
    DATA
group by
    "USER", 
    extract(hour from "TIME")
;

结果当然是:

USER  |Hour|COUNT
------+----+-----
Marion|   8|    1
Marion|  15|    2
Martin|  14|    1
Martin|  15|    2

但是,如何以一小时的间隔获取每个用户一整天的事件数量?像这样:

USER  |Hour|COUNT
------+----+-----
Marion|   0|    0
Marion|   1|    0
...
Marion|   7|    0
Marion|   8|    1
Marion|   9|    0
...
Marion|  14|    0
Marion|  15|    2
Marion|  16|    0
...
Marion|  22|    0
Marion|  23|    0
Martin|   0|    0
Martin|   1|    0
...
Martin|  13|    0
Martin|  14|    1
Martin|  15|    2
Martin|  16|    0
...
Martin|  22|    0
Martin|  23|    0

BTW我不会对所涉及的任何数据库进行写访问。

2 个答案:

答案 0 :(得分:5)

你想要做这样的事情,创建一个数字为0到23的(临时)表HOURS,然后做一个外连接以获得所有的HOUR值,无论它们是否在DATA

select 
    "USER", 
    extract(hour from "TIME") as "Hour",
    SUM(CASE WHEN Data.HOUR is NOT NULL 1 ELSE 0 END)
from 
    DATA
    right outer join HOURS on extract(hour from "TIME") = HOURS.hour
group by
    "USER", 
    extract(hour from "TIME")
;

如果你不能创建一个表,你可以做一些丑陋的事情,比如

(SELECT 1 as hour UNION 2 ... UNION 23) as HOURS

虽然根据你的方言可能有更好的方法来做到这一点

答案 1 :(得分:0)

@ spinning_plate的答案适用于垂直答案(两种方式 - 临时表或工会)

您可能也想要一个水平结果 - 即标题:user | 0000 | 0100 | 0200 | ...... | 2200 | 2300

如果是这样,那么有些选择......

使用SQL-Server 2005+或Oracle 11g +,查看PIVOT / UNPIVOT

使用Oracle< 11g,查看DECODE(例如:

SELECT
   ...
   SUM(DECODE(extract(hour from "TIME"),1,1,0)) as 0100,
   SUM(DECODE(extract(hour from "TIME"),13,1,0)) as 1300,
...