我有一个基于CTE的查询,我在其中检索两个给定时间跨度之间的每小时间隔。我的查询工作如下:
获取开始和结束日期时间(比如说07-13-2011 00:21:09和07-31-2011 21:11:21)获取每小时间隔之间的每小时总查询值(此处为00到00) 21,总共21个小时,但这是参数,取决于我为每天输入的小时数。
此查询适用于第一个时间戳的小时小于第二个时间的输入-e.g.上午03点是第一个时间戳的小时,上午07点是第二个时间戳的小时,但是有一个问题。当我想检索输入的总计数时,例如07-13-2011 22:11:43和07-25-2011 04:06:04,我遇到了问题。我需要检索以下查询的总计数:
07-13-2011 22:00:00 143 //representing the total amounts of queries 22:11:43 - 22:59:59 interval-
07-13-2011 23:00:00 121 //representing the total amounts of queries in 23:00:00 -23:59:59 interval-
07-14-2011 00:00:00 65 //00:00:00 - 00:59:59 interval
07-14-2011 01:00:00 51 //01:00:00 - 01:59:59 interval...
.
.
.
07-14-2011 04:00:00 22 //query amount for 04:00:00 - 04:06:04 interval
等等。除了我在下面写的CTE查询之外,我还需要做什么?
WITH cal AS (
SELECT generate_series('2011-02-02 00:00:00'::timestamp
, '2012-04-01 05:00:00'::timestamp
, '1 hour'::interval) AS stamp
)
, qqq AS (
SELECT date_trunc('hour', calltime) AS stamp
, count(*) AS zcount
FROM mytable
WHERE calltime >= '07-13-2011 22:00:00'
AND calltime <='07-31-2011 04:33:21'
AND calltime::time >= '22:00:00'
AND calltime::time <= '04:33:21'
-- this calltime::time part obviously doesn't work due to common sense and logic
-- edited it to show what I try to mean
AND date_part('hour', calltime) >= 0
AND date_part('hour', calltime) <= 21
GROUP BY date_trunc('hour', calltime)
)
SELECT cal.stamp
, COALESCE (qqq.zcount, 0) AS zcount
FROM cal
LEFT JOIN qqq ON cal.stamp = qqq.stamp
WHERE cal.stamp >= '07-13-2011 22:00:00'
AND cal.stamp<='07-31-2011 04:33:21'
AND date_part('hour', cal.stamp) >= 0
AND date_part('hour', cal.stamp) <= 21
ORDER BY stamp ASC;
答案 0 :(得分:2)
考虑这个修正版本:
WITH param AS (
SELECT '2011-07-13 22:11:43'::timestamp AS start -- supply start / stop once
,'2011-07-25 04:06:04'::timestamp AS stop
)
, cal AS (
SELECT generate_series(date_trunc('hour', p.start)
,date_trunc('hour', p.stop + interval '1h')
,interval '1h') AS h
FROM param p
)
, q AS (
SELECT date_trunc('hour', calltime) AS h
,count(*) AS ct
FROM mytable
,param p
WHERE calltime >= p.start
AND calltime <= p.stop
-- uncomment if you actually want to exclude hours 22 & 23 (?)
-- AND extract('hour' FROM calltime) BETWEEN 0 AND 21
GROUP BY 1
)
SELECT cal.h, COALESCE(q.ct, 0) AS ct
FROM cal
LEFT JOIN q USING (h)
-- uncomment if you actually want to exclude hours 22 & 23 (?)
-- WHERE extract('hour' FROM cal.h) BETWEEN 0 AND 21
ORDER BY 1;
主要变化是立即从实际时间跨度中产生小时数 删除了一些不必要的条件 使用ISO 8601格式表示时间戳(适用于所有语言环境)。
在此related answer查找更多上下文和链接。唯一的区别是:在那里它是关于运行计数。
答案 1 :(得分:1)
本条:
AND calltime::time >= '00:21:09' AND calltime::time <= '21:11:21'
鉴于其他条款,看起来很可疑。
目前尚不清楚为什么需要它,如果分别以22:11:43
和04:06:04
作为示例给出的字面时间不起作用,则此子句将过滤掉所有内容,以便您结束每小时最多0个计数。