你如何在基于oracle的sql中汇总数据?

时间:2016-11-15 16:43:37

标签: sql oracle

我有一个名为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查询吗?

5 个答案:

答案 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);