[英]sql query to count person in each hour separately
I have a table which has theses fields: 我有一个包含这些字段的表:
id | person_id | start_time | end_time | status
I want to get number of people which exists in each hour in a specific day, something like below pseudo code: 我想获取特定日期每一小时中存在的人数,例如下面的伪代码:
select count(person) from table where dow of end_time=day and end_time >= hour and start_time < hour+1 for hour in working hours of organization and day is a certain day of week
If it would be possible to have a temporary table which consists of hours of a day may be the following solution is a solution: 如果可能有一个由一天中的几个小时组成的临时表,则可以采用以下解决方案:
select t.h, count(s.id)
from
session s cross join (temperoray table with one column of hours in a day as t)
where
s.start_time < (t.h + 1) and s.end_time > t.h
group by
t.h
But I do not know a command which could create a temporary table as I needed. 但是我不知道可以根据需要创建临时表的命令。
I found this question which is very similar to what I want but all of its solution is based on group by
which I do not think makes any sense in my case because parts of each group has common items, eg, a person could count as person in hour 11 and person in hour 12 and 13. 我发现这个问题与我想要的问题非常相似,但是它的所有解决方案都是基于
group by
,在我的情况下,我认为这没有任何意义,因为每个组的各个部分都有共同的项目,例如,一个人可以算作一个人在第11小时,在第12和13小时的人。
I hope that I can find a way that gets me a table like this: 我希望我能找到一种使我得到如下表格的方式:
hour |number of persons
10 |2
11 |0
12 |3
13 |1
...
Notice that it may possible to have some day with zero number of persons. 请注意,某天的人数可能为零。
id | status | start_time | end_time | branch_id | person_id | session_type
------+--------+----------------------------------+----------------------------------+-----------+-----------+--------------
2675 | FI | 2018-04-23 10:30:50.939693+04:30 | 2018-04-23 12:31:39.340692+04:30 | 1 | 1085 | IN
2676 | FI | 2018-04-23 11:47:06.683374+04:30 | 2018-04-23 13:23:52.659714+04:30 | 1 | 2722 | IN
2677 | FI | 2018-04-23 11:47:59.341765+04:30 | 2018-04-23 13:25:46.339266+04:30 | 1 | 2721 | IN
2678 | FI | 2018-04-23 11:58:34.854222+04:30 | 2018-04-23 13:25:55.08795+04:30 | 1 | 2723 | IN
2679 | FI | 2018-04-23 12:27:58.817234+04:30 | 2018-04-23 13:12:28.278699+04:30 | 1 | 2724 | IN
2680 | FI | 2018-04-23 12:30:36.552407+04:30 | 2018-04-23 12:30:54.088159+04:30 | 1 | 2725 | IN
2681 | FI | 2018-04-23 14:55:50.886725+04:30 | 2018-04-23 16:08:27.076629+04:30 | 1 | 25 | IN
2682 | FI | 2018-04-23 15:06:30.443347+04:30 | 2018-04-23 15:52:20.128546+04:30 | 1 | 2653 | IN
2683 | FI | 2018-04-23 15:21:57.979387+04:30 | 2018-04-23 16:16:09.289267+04:30 | 1 | 2580 | IN
2684 | FI | 2018-04-23 15:26:18.057999+04:30 | 2018-04-23 16:02:44.704133+04:30 | 1 | 2726 | IN
2685 | FI | 2018-04-23 16:50:10.2957+04:30 | 2018-04-23 17:23:01.732404+04:30 | 1 | 2727 | IN
2686 | FI | 2018-04-23 16:52:28.474299+04:30 | 2018-04-23 17:23:51.013318+04:30 | 1 | 2728 | IN
2687 | FI | 2018-04-23 16:58:05.796563+04:30 | 2018-04-23 17:33:03.259335+04:30 | 1 | 1646 | IN
2688 | FI | 2018-04-23 17:50:02.738009+04:30 | 2018-04-23 18:43:27.152203+04:30 | 1 | 2729 | IN
2689 | FI | 2018-04-23 18:47:12.19468+04:30 | 2018-04-23 19:25:46.606731+04:30 | 1 | 2730 | IN
2690 | FI | 2018-04-23 19:18:32.922065+04:30 | 2018-04-23 20:11:26.703693+04:30 | 1 | 2408 | IN
2691 | FI | 2018-04-23 19:18:53.133712+04:30 | 2018-04-23 19:56:47.702305+04:30 | 1 | 2409 | IN
2692 | FI | 2018-04-23 19:21:00.348889+04:30 | 2018-04-23 20:24:25.882451+04:30 | 1 | 2731 | IN
2693 | FI | 2018-04-23 19:30:05.908247+04:30 | 2018-04-23 20:12:36.627888+04:30 | 1 | 2591 | IN
2694 | FI | 2018-04-23 19:36:02.700379+04:30 | 2018-04-23 20:13:35.146002+04:30 | 1 | 2732 | IN
2695 | FI | 2018-04-23 19:50:15.13214+04:30 | 2018-04-23 20:09:37.168147+04:30 | 1 | 2491 | IN
2696 | FI | 2018-04-23 19:51:54.754169+04:30 | 2018-04-23 20:09:59.029376+04:30 | 1 | 2733 | IN
2697 | FI | 2018-04-23 19:53:13.529475+04:30 | 2018-04-23 20:09:49.229139+04:30 | 1 | 2734 | IN
2698 | FI | 2018-04-23 19:59:27.70488+04:30 | 2018-04-23 20:21:47.862433+04:30 | 1 | 1762 | IN
2699 | FI | 2018-04-23 19:59:57.86605+04:30 | 2018-04-23 20:22:05.171377+04:30 | 1 | 1761 | IN
2700 | FI | 2018-04-23 20:24:21.212784+04:30 | 2018-04-23 20:47:31.854373+04:30 | 1 | 2735 | IN
2701 | FI | 2018-04-23 21:58:57.308547+04:30 | 2018-04-23 22:43:20.075321+04:30 | 1 | 1705 | IN
2702 | FI | 2018-04-23 21:59:44.974384+04:30 | 2018-04-23 22:43:45.946989+04:30 | 1 | 1704 | IN
2703 | FI | 2018-04-23 22:10:20.991216+04:30 | 2018-04-23 22:40:51.16409+04:30 | 1 | 2711 | IN
And I which to get results for this day as below: 而我今天要得到的结果如下:
hour | number
10 | 1
11 | 4
12 | 6
13 | 4
14 | 1
15 | 4
16 | 6
17 | 4
18 | 2
19 | 11
20 | 10
21 | 2
22 | 3
If I understand correct 如果我理解正确
you need to use generate_series
function to create 24 hour then left join
it. 您需要使用
generate_series
函数创建24小时,然后left join
。
You can add some condition on Where
clause. 您可以在
Where
子句中添加一些条件。
Get by Hour 按小时获取
SELECT gs.hours,
Sum(
CASE
WHEN start_time IS NOT NULL THEN 1
WHEN end_time IS NOT NULL THEN 1
ELSE 0
END ) AS "count"
FROM (
SELECT hours
FROM Generate_series(1,24) AS gs(hours) ) gs
LEFT JOIN
(
SELECT *,
Generate_series(start_time::timestamp, end_time::timestamp, '1 hours') invhour
FROM t )t
ON gs.hours = To_char(t.invhour,'HH24')::integer
GROUP BY gs.hours
Get by Hour and Date 按小时和日期获取
SELECT To_char(t.invhour,'yyyy-MM-dd') AS "dates",
gs.hours,
Sum(
CASE
WHEN start_time IS NOT NULL THEN 1
WHEN end_time IS NOT NULL THEN 1
ELSE 0
END ) AS "count"
FROM (
SELECT hours
FROM Generate_series(1,24) AS gs(hours) ) gs
LEFT JOIN
(
SELECT *,
Generate_series(start_time::timestamp, end_time::timestamp, '1 hours') invhour
FROM t )t
ON gs.hours = To_char(t.invhour,'HH24')::integer
GROUP BY gs.hours,
to_char(t.invhour,'yyyy-MM-dd')
sqlfiddle: http://sqlfiddle.com/#!17/717fa/1 sqlfiddle: http ://sqlfiddle.com/#!17/717fa/1
You will need to create a set for the 24 hours, then do a left join and a group by hour. 您将需要为24小时创建一个集合,然后按小时进行左连接和分组。
Someone here has suggested using generate_series in a subquery, but personally I think recursive ctes are a little nicer for creating ranges. 这里有人建议在子查询中使用generate_series,但就我个人而言,我认为递归ctes对于创建范围会更好一些。 This way you can keep the series set outside the main query, making it a little easier to understand and maintain.
这样,您可以将系列设置保留在主查询之外,从而使其更易于理解和维护。
; WITH RECURSIVE Hours AS
(
SELECT 1 AS hour
UNION ALL
SELECT hour + 1 FROM Hours WHERE Hour < 24
)
SELECT hour, COUNT(person_id)
FROM Hours
LEFT JOIN T on hour BETWEEN extract(hour from start_time) AND extract(hour from end_time)
GROUP BY hour
ORDER BY hour
http://sqlfiddle.com/#!17/717fa/12/0 http://sqlfiddle.com/#!17/717fa/12/0
Using the generate_series from D-Shih's answer I get the following solutions. 使用D-Shih的答案的generate_series,我得到以下解决方案。
This first solution shows all hours when at least one person was working. 第一个解决方案显示了至少一个人在工作的所有时间。
select Hour, count(1) as "Users"
from generate_series(1,24) as gs (Hour)
join Log as l
on date_part('hour',l.TimeFrom) <= gs.Hour
and date_part('hour',l.TimeTo) >= gs.Hour
group by Hour
order by Hour;
If you also need the hours when nobody was working, use a left join
. 如果您还需要没有人工作的时间,请使用
left join
。 This requires a change to the count()
to only count when a record is found. 这要求对
count()
进行更改,以便仅在找到记录时才进行计数。
select Hour, count(case when l.UserId is not null then 1 end) as "Users"
from generate_series(1,24) as gs (Hour)
left join Log as l
on date_part('hour',l.TimeFrom) <= gs.Hour
and date_part('hour',l.TimeTo) >= gs.Hour
group by Hour
order by Hour;
See this SQL Fiddle for some example data and output. 有关一些示例数据和输出,请参见此SQL Fiddle 。
Look at this article which walks through creating a Temp table in PostgreSQL (I am a SQL server person). 请看这篇文章 ,其中逐步介绍了在PostgreSQL中创建一个Temp表的过程(我是一名SQL Server人员)。
Have one column which is the hours of the day and I think your method of joining it to your table would work. 只有一栏是一天中的小时,我认为您可以将其连接到表中。
It also depends on your data in that table too. 这也取决于您在该表中的数据。 Can you provide a top 1 row data to get an idea of how it looks like?
您可以提供前1行的数据来了解它的外观吗? You might not even need the temp table.
您甚至可能不需要临时表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.