我有一个名为login的oracle表,其列名为as_time,条目为timestamp(6)数据类型:
15-NOV-16 11.01.43.255000000 AM
我需要一个select语句,用于计算过去30天内每15分钟记录的数量。
输出必须如下:
Time Count
11/01/2016 00:00:00 10
11/01/2016 00:15:00 10
11/01/2016 00:30:00 50
11/01/2016 00:45:00 70
11/01/2016 01:00:00 10
11/01/2016 01:15:00 10
11/01/2016 01:30:00 10
11/01/2016 02:45:00 160
有人可以帮忙构建SQL查询吗?
答案 0 :(得分:1)
试试这个 - 将时间戳向下舍入到最接近的15分钟,然后总结:
WITH
test_data (as_time) AS
(SELECT
CAST(sysdate + (rownum/24/60) AS TIMESTAMP)
FROM
all_objects
WHERE rownum < 150
)
SELECT
TO_CHAR(TO_DATE(date_hour||':'||mins_rounded_down,'YYYY/MM/DD HH24:MI'),'YYYY/MM/DD HH24:MI') rounded_date
,COUNT(*)
FROM
(SELECT
as_time
,TO_CHAR(as_time,'YYYY/MM/DD HH24:MI') date_time
,TO_CHAR(as_time,'YYYY/MM/DD HH24') date_hour
,TO_CHAR(as_time,'MI') real_mins
,TO_CHAR(MOD(FLOOR(TO_NUMBER(TO_CHAR(as_time,'MI'))/15)*15,60),'FM00') mins_rounded_down
FROM
test_data
)
WHERE 1=1
AND as_time > sysdate - 30
GROUP BY
date_hour
,mins_rounded_down
;
答案 1 :(得分:1)
鉴于你已经提取了日期的部分,除了分钟和秒(例如使用to_char
) - 剩下的全部基本上都是为了处理分钟。
如果tbl是“提取”之后的数据集,并且您不关心将日期作为字符串处理(您可以始终使用to_date
来转换它),这里是一个合适的SQL查询:
select dt_without_mins||floor(to_char(dt, 'mi') / 15) * 15, count(*)
from tbl
group by dt_without_mins||floor(to_char(dt, 'mi') / 15);
答案 2 :(得分:1)
这样的事情应该有效。在子查询中创建时间表,基于时间比较加入,并按分组计数;连接是用于数据密集化的左外连接(仍然包括没有活动的时间间隔,计数为0)。
select t.time_from, coalesce(count(*), 0) as ct
from (
select trunc(sysdate) - 30 + (level-1)/(24*4),
trunc(sysdate) - 30 + level/(24*4)
from dual
connect by level <= 30*24*4
) t
left outer join login l
on l.as_time >= t.time_from and l.as_time < t.time_to
group by t.time_from
order by t.time_from
;
答案 3 :(得分:0)
一种方法是截断到最接近的小时,然后分别处理分钟:
select trunc(as_time, 'HH') as yyyymmddhh,
floor(extract(minute from as_time) / 15)*15 as mm,
count(*)
from t
group by trunc(as_time, 'HH'),
floor(extract(minute from as_time)
order by 1, 2;
注意:
as_date > sysdate - interval '30' day
。答案 4 :(得分:0)
这是一个更通用的方法:
CREATE OR REPLACE FUNCTION MakeInterval(ts IN TIMESTAMP, roundInterval IN INTERVAL DAY TO SECOND) RETURN TIMESTAMP DETERMINISTIC IS
denom INTEGER;
BEGIN
IF roundInterval >= INTERVAL '1' HOUR THEN
denom := EXTRACT(HOUR FROM roundInterval);
IF MOD(24, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts) + TRUNC(EXTRACT(HOUR FROM ts) / denom) * denom * INTERVAL '1' HOUR;
ELSIF roundInterval >= INTERVAL '1' MINUTE THEN
denom := EXTRACT(MINUTE FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'hh') + TRUNC(EXTRACT(MINUTE FROM ts) / denom) * denom * INTERVAL '1' MINUTE;
ELSE
denom := EXTRACT(SECOND FROM roundInterval);
IF MOD(60, denom) <> 0 THEN
RAISE VALUE_ERROR;
END IF;
RETURN TRUNC(ts, 'mi') + TRUNC(EXTRACT(SECOND FROM ts) / denom) * denom * INTERVAL '1' SECOND;
END IF;
END MakeInterval;
select
MakeInterval(as_time, INTERVAL '15' MINUTE) as time,
count(*) AS count
from the_table
where as_time > sysdate - 30
group by MakeInterval(as_time, INTERVAL '15' MINUTE);