POSTGRES SQL计数范围为两个日期

时间:2016-11-29 10:40:59

标签: sql postgresql

我想计算两个日期之间的范围,例如:

  AGENT   | LOGIN_START          | LOGIN_END
  --------+----------------------+---------------------
  101     |  2016-01-01 06:00:00 | 2016-01-01 06:29:59
  102     |  2016-01-01 06:00:00 | 2016-01-01 08:20:00
  103     |  2016-01-01 06:00:00 | 2016-01-01 06:01:00
  101     |  2016-01-01 10:00:00 | 2016-01-01 10:01:00
  101     |  2016-01-01 10:02:00 | 2016-01-01 10:03:00

并在30分钟之间分隔小时数并按代理人计算

  TIME            | LOGIN_QTY         
  ----------------+-----------
  06:00 - 06:30   |  3
  06:30 - 07:00   |  1
  07:00 - 07:30   |  1
  07:30 - 08:00   |  1
  08:00 - 08:30   |  1
  10:00 - 10:30   |  1

我正在尝试使用此SQL但是不可能获得超过30分钟的范围,例如:代理102从6:00到8:20在线,并且需要计算范围 => 06:00 - 06:30,06:30 - 07:00,07:00 - 07:30,07:30 - 08:00,08:00 - 08:30

这是我的SQL

SELECT 
count(agente)
agente,
to_char(to_timestamp(floor((extract('epoch' from datahora_ini) / 1800 )) * 1800) AT TIME ZONE 'UTC','HH24MI') 
FROM callcenter.agente_login
group by agente,  to_char(to_timestamp(floor((extract('epoch' from datahora_ini) / 1800 )) * 1800) AT TIME ZONE 'UTC','HH24MI') 

******************** UPDATE *********************

我运行了Marth和RémyBaron的sql解决方案 仍然没有工作....

Interval 2016-10-03 14:30:00 - 2016-10-03 15:00:00在线2个代理商,不是一个......

示例:

|| *datahora_ini*      || *datahora_fim*      ||agent||
|| 2016-10-03 09:19:07 || 2016-10-03 19:21:06 || 109 ||
|| 2016-10-03 09:19:07 || 2016-10-03 09:19:50 || 109 ||
|| 2016-10-03 09:32:03 || 2016-10-03 10:40:44 || 138 ||
|| 2016-10-03 09:32:03 || 2016-10-03 09:32:46 || 138 ||
|| 2016-10-03 10:43:32 || 2016-10-03 13:14:55 || 138 ||
|| 2016-10-03 10:43:32 || 2016-10-03 10:44:15 || 138 ||
|| 2016-10-03 14:51:11 || 2016-10-03 17:07:56 || 138 ||
|| 2016-10-03 14:51:11 || 2016-10-03 14:51:53 || 138 ||
|| 2016-10-03 17:07:26 || 2016-10-03 17:08:08 || 138 ||
|| 2016-10-03 17:08:08 || 2016-10-03 17:13:16 || 138 ||
|| 2016-10-03 17:14:55 || 2016-10-03 17:15:38 || 138 ||
|| 2016-10-03 17:15:38 || 2016-10-03 18:51:50 || 138 ||

sql result ....

|| *interval*                                ||Cnt||
|| 2016-10-03 12:30:00 - 2016-10-03 13:00:00 || 2 ||
|| 2016-10-03 13:00:00 - 2016-10-03 13:30:00 || 2 ||
|| 2016-10-03 13:30:00 - 2016-10-03 14:00:00 || 1 ||
|| 2016-10-03 14:00:00 - 2016-10-03 14:30:00 || 1 ||
|| 2016-10-03 14:30:00 - 2016-10-03 15:00:00 || 1 ||
|| 2016-10-03 15:00:00 - 2016-10-03 15:30:00 || 2 ||
|| 2016-10-03 15:30:00 - 2016-10-03 16:00:00 || 2 ||
|| 2016-10-03 16:00:00 - 2016-10-03 16:30:00 || 2 ||
|| 2016-10-03 16:30:00 - 2016-10-03 17:00:00 || 2 ||
|| 2016-10-03 17:00:00 - 2016-10-03 17:30:00 || 2 ||
|| 2016-10-03 17:30:00 - 2016-10-03 18:00:00 || 2 ||
|| 2016-10-03 18:00:00 - 2016-10-03 18:30:00 || 2 ||
|| 2016-10-03 18:30:00 - 2016-10-03 19:00:00 || 2 ||
|| 2016-10-03 19:00:00 - 2016-10-03 19:30:00 || 1 ||
|| 2016-10-03 19:30:00 - 2016-10-03 20:00:00 || 0 ||
|| 2016-10-03 20:00:00 - 2016-10-03 20:30:00 || 0 ||
|| 2016-10-03 20:30:00 - 2016-10-03 21:00:00 || 0 ||
|| 2016-10-03 21:00:00 - 2016-10-03 21:30:00 || 0 ||
|| 2016-10-03 21:30:00 - 2016-10-03 22:00:00 || 0 ||
|| 2016-10-03 22:00:00 - 2016-10-03 22:30:00 || 0 ||
|| 2016-10-03 22:30:00 - 2016-10-03 23:00:00 || 0 ||
|| 2016-10-03 23:00:00 - 2016-10-03 23:30:00 || 0 ||

SQL:

WITH min_max_time AS (
  SELECT MIN(datahora_ini::timestamp(0) ), MAX(datahora_fim::timestamp(0) )
  FROM callcenter.agente_login
), periods(time) AS (
  SELECT generate_series(min, max, '30 minutes'::interval)
  FROM min_max_time
)
SELECT
  time || ' - ' || (time + '30 minutes'::interval) as intervalo,
  COUNT(CASE WHEN datahora_ini::timestamp(0)  <= time AND datahora_fim::timestamp(0)  >= time THEN 1 else null end)
FROM callcenter.agente_login, periods
GROUP BY time
ORDER BY time

1 个答案:

答案 0 :(得分:2)

使用FILTER(PostgreSQL 9.4+)将COUNT(*)限制为您想要的行:

WITH min_max_time AS (
  SELECT MIN(login_start), MAX(login_end)
  FROM agents
), periods(time) AS (
  SELECT generate_series(min, max, '30 minutes'::interval)
  FROM min_max_time
)
SELECT
  time || ' - ' || (time + '30 minutes'::interval),
  COUNT(*) FILTER ( WHERE 
    tsrange(login_start, login_end, '[]') && tsrange(time, time + '30 minutes'::interval, '[]')
  )
FROM agents, periods
GROUP BY time
ORDER BY time
;
┌───────────────────────────────────────────┬───────┐
│                 ?column?                  │ count │
├───────────────────────────────────────────┼───────┤
│ 2016-01-01 06:00:00 - 2016-01-01 06:30:00 │     3 │
│ 2016-01-01 06:30:00 - 2016-01-01 07:00:00 │     1 │
│ 2016-01-01 07:00:00 - 2016-01-01 07:30:00 │     1 │
│ 2016-01-01 07:30:00 - 2016-01-01 08:00:00 │     1 │
│ 2016-01-01 08:00:00 - 2016-01-01 08:30:00 │     1 │
│ 2016-01-01 08:30:00 - 2016-01-01 09:00:00 │     0 │
│ 2016-01-01 09:00:00 - 2016-01-01 09:30:00 │     0 │
│ 2016-01-01 09:30:00 - 2016-01-01 10:00:00 │     0 │
│ 2016-01-01 10:00:00 - 2016-01-01 10:30:00 │     1 │
└───────────────────────────────────────────┴───────┘
(9 rows)