重写 9.2 版的查询

sea*_*abr 1 postgresql postgresql-9.2

我想计算两个日期之间的范围,就像这个例子:

  代理 | 登录_开始 | 登录_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 分钟和代理之间分开几个小时,只是一个例子:

  时间 | 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

问题:代理 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:

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
;
Run Code Online (Sandbox Code Playgroud)

结果:

?????????????????????????????????????????????????????? ???
? ?柱子?? 数数 ?
?????????????????????????????????????????????????????? ???
? 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.4+ 之前的 Postgres 版本重写查询。

ype*_*eᵀᴹ 5

唯一的问题似乎是FILTER条款。你可以重写:

COUNT(*) FILTER ( WHERE tsrange(login_start, login_end, '[]') 
                  && tsrange(time, time + '30 minutes'::interval, '[]')
                )
Run Code Online (Sandbox Code Playgroud)

作为:

COUNT(CASE WHEN tsrange(login_start, login_end, '[]') 
                && tsrange(time, time + '30 minutes'::interval, '[]')
           THEN 1 END
     )
Run Code Online (Sandbox Code Playgroud)

我也会使用包含-排除间隔:[). 否则某些行将被计算两次。