按60分钟的滑动窗口分组

时间:2011-08-22 20:49:46

标签: sql oracle group-by

我有一张表格,里面有关于工作的信息:工作类型,开始时间和结束时间。

我想要一份报告,告诉我每小时有多少工作 - 但不是时钟时间,而是距离该组第一份工作时间60分钟的非工作时间(他们是一批工作,所以我确切地知道工作类型不会在时间上重叠。

这样的事情:

num_of_jobs | job_type | hour
-----------------------------
1254        | B        | 2011-08-22 13:47
9983        | B        | 2011-08-22 14:47
9072        | B        | 2011-08-22 15:47
20309       | B        | TOTAL
79          | C        | 2011-08-22 16:02
105         | C        | 2011-08-22 17:02
184         | C        | TOTAL
10234       | D        | 2011-08-22 17:29
9882        | D        | 2011-08-22 18:29
20116       | D        | TOTAL

如果可以按小时分组(例如12:00,13:00,14:00),我可以很容易地这样做(非常简化的实际查询版本):

select count(job_id) number_of_jobs, job_type,
    case when to_char(end_date,'YYYY-MM-DD HH24') is not null
         then to_char(end_date,'YYYY-MM-DD HH24')||':00'
         else 'TOTAL'
    end Date_and_hour
from my_jobs
where end_date is not null
group by rollup (to_char(end_date,'YYYY-MM-DD HH24')) , job_type
order by to_char(end_date,'YYYY-MM-DD HH24') asc, job_type asc;

除了小时数上的小组,而不是基于job_type的批次中最小的开始时间。

我真的不太确定如何让这个工作。

(使用Oracle 10g)

1 个答案:

答案 0 :(得分:2)

在我看来,真正的问题在于找出每行所属的小时组。完成后,您可以将其插入您提供的查询中以获得最终答案。要获得小时组,我们所要做的就是弄清楚自小组最早时间以来已经过了多少小时:

select floor((end_date - min(end_date) 
                         over (partition by job_type))*24)+1 as hour_group
from my_jobs
where end_date is not null

我正在使用trunc,因为我们只关心整个小时并添加一个,以便我们从一开始计数,而不是零。由于此解决方案使用分析函数,因此您需要在分组之前将其放在子查询中。


稍微玩一下,我最终会得到以下(未经测试的)查询:

SELECT   COUNT(job_id) number_of_jobs, 
         job_type, 
         min_time + FLOOR((end_date - min_time) * 24) / 24 AS date_and_hour
FROM     (SELECT job_id, 
                 job_type, 
                 end_date, 
                 MIN(end_date) OVER (PARTITION BY job_type) AS min_time
          FROM   my_jobs
          WHERE  end_date IS NOT NULL)
GROUP BY ROLLUP(min_time + FLOOR((end_date - min_time) * 24) / 24), job_type
ORDER BY hour_group ASC, job_type ASC;

原理与我最初的答案相同,我只是稍微调整一下数学。