按时间分组,每天24小时

时间:2021-09-13 02:56:52

Given the following declarations where there is a registration of an arbitrary event for a user (USER) at a given time (TIME) in a table DATA:

给定以下声明,其中在表数据中的给定时间(时间)为用户(用户)注册了任意事件:

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');

It's trivial to find the number of events per user at a given one-hour period:

在给定的一小时内找到每个用户的事件数是很简单的:

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

The result is, of course:

结果当然是:

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

But how do I get the number of events per user across an entire day in one hour intervals? Like this:

但是,如何在一小时的间隔内得到一天中每个用户的事件数呢?是这样的:

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 I won't have write access to any database involved.

顺便说一下,我不会写任何涉及到的数据库。

2 个解决方案

#1


5  

You would want to do something like this, create a (temp) table HOURS with the numbers 0 to 23, then do an outer join to get all the HOUR values regardless of whether they are in DATA

您可能想做这样的事情,创建一个(temp)表小时,其中的数字为0到23,然后执行外部连接以获取所有的小时值,而不管它们是否在数据中

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")
;

If you can't create a table, you can do ugly things like

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

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

though there might be better way to do this depending your dialect

虽然可能有更好的方法根据你的方言

#2


0  

@spinning_plate's answer is good for a vertical answer (both ways -- temp table, or unions)

@spinning_plate的答案对于垂直的答案是好的(两种方法——临时表或联合)

You might also like a horizontal result -- i.e. with headers: user | 0000 | 0100 | 0200 | ... | 2200 | 2300

您可能还希望得到一个水平结果——例如,使用header: user | 0000 | 0100 | 0200 |…| 2200 | 2300

If so, then some options...

如果是的话,那么一些选择……

with SQL-Server 2005+ or Oracle 11g+, look into PIVOT / UNPIVOT

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

with Oracle <11g, look into DECODE (e.g.:

使用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,
...

#1


5  

You would want to do something like this, create a (temp) table HOURS with the numbers 0 to 23, then do an outer join to get all the HOUR values regardless of whether they are in DATA

您可能想做这样的事情,创建一个(temp)表小时,其中的数字为0到23,然后执行外部连接以获取所有的小时值,而不管它们是否在数据中

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")
;

If you can't create a table, you can do ugly things like

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

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

though there might be better way to do this depending your dialect

虽然可能有更好的方法根据你的方言

#2


0  

@spinning_plate's answer is good for a vertical answer (both ways -- temp table, or unions)

@spinning_plate的答案对于垂直的答案是好的(两种方法——临时表或联合)

You might also like a horizontal result -- i.e. with headers: user | 0000 | 0100 | 0200 | ... | 2200 | 2300

您可能还希望得到一个水平结果——例如,使用header: user | 0000 | 0100 | 0200 |…| 2200 | 2300

If so, then some options...

如果是的话,那么一些选择……

with SQL-Server 2005+ or Oracle 11g+, look into PIVOT / UNPIVOT

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

with Oracle <11g, look into DECODE (e.g.:

使用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,
...