对于 Oracle,一种方法是模型子句(当我们组成行时,模型子句可以为我们做到这一点)。
一些东西。您似乎只想要精确到分钟的数据,因此为此使用日期与时间戳是有意义的。其次,我会避免在 oracle 的表中使用区分大小写的名称(在下面的查询中,我将您的数据别名回不敏感,以使其更容易编码:))
SQL> with data as (select rownum id, "SensorKey" s_key, cast("StartTime" as date) s_time, cast("EndTime" as date) e_time,
2 ((trunc(cast("EndTime" as date) , 'hh24') -trunc(cast("StartTime" as date), 'hh24')) *24)+1 hours
3 from table1)
4 select to_char(block_start, 'yyyymmdd') "TimeKey",
5 thehour "Hour", s_key "SensorKey",
6 sum(duration) "Duration", min(s_time) "StartTime", max(e_time) "EndTime"
7 from (select block_start, thehour, s_key, duration, s_time, e_time
8 from data
9 model partition by (id as key)
10 dimension by (0 as f)
11 measures (s_key, s_time, e_time,
12 cast(2 as number(2,0)) duration, hours,
13 cast(null as number(2)) thehour,
14 cast(null as date) block_start,
15 cast(null as date) block_end)
16 rules (block_start[for f from 0 to hours[0]-1 increment 1] = trunc(s_time[0] + (cv(f)/24), 'hh24'),
17 block_end[any] = trunc(s_time[0] + ((cv(f)+1)/24), 'hh24'),
18 s_key[any] = s_key[0],
19 s_time[any] = s_time[0],
20 e_time[any] = e_time[0],
21 duration [any] = case
22 when cv(f) = 0
23 then (least(block_end[cv(f)],e_time[0]) - s_time[0]) * 24*60
24 when cv(f) = hours[0]-1
25 then (e_time[0] - block_start[cv(f)] ) * 24*60
26 else (block_end[cv(f)] - block_start[cv(f)] ) * 24*60
27 end,
28 thehour[any] = to_char(s_time[0] + (cv(f)/24), 'hh24')
29 ))
30 group by block_start, thehour, s_key
31 order by 5, 2;
TimeKey Hour SensorKey Duration StartTime EndTime
-------- ---------- ---------- ---------- ----------------- -----------------
20121017 8 45 29 17-oct-2012 08:31 17-oct-2012 10:21
20121017 9 45 60 17-oct-2012 08:31 17-oct-2012 10:21
20121017 10 45 46 17-oct-2012 08:31 17-oct-2012 10:51
20121017 12 45 24 17-oct-2012 12:21 17-oct-2012 13:41
20121017 13 45 50 17-oct-2012 12:41 17-oct-2012 14:46
20121017 14 45 46 17-oct-2012 13:51 17-oct-2012 14:46
20121017 15 45 19 17-oct-2012 15:11 17-oct-2012 16:21
20121017 16 45 21 17-oct-2012 15:46 17-oct-2012 16:21
20121017 18 45 5 17-oct-2012 18:51 17-oct-2012 18:56
20121017 19 45 45 17-oct-2012 19:11 17-oct-2012 19:56
20121017 20 45 34 17-oct-2012 20:26 17-oct-2012 21:11
20121017 21 45 11 17-oct-2012 20:26 17-oct-2012 21:11
20121017 22 45 35 17-oct-2012 22:16 17-oct-2012 22:56
20121018 0 45 60 17-oct-2012 23:36 18-oct-2012 01:46
20121018 1 45 46 17-oct-2012 23:36 18-oct-2012 01:46
20121017 23 45 24 17-oct-2012 23:36 18-oct-2012 01:46
20121018 2 45 40 18-oct-2012 02:16 18-oct-2012 02:56
20121018 3 45 29 18-oct-2012 03:31 18-oct-2012 15:06
20121018 4 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 5 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 6 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 7 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 8 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 9 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 10 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 11 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 12 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 13 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 14 45 60 18-oct-2012 03:31 18-oct-2012 15:06
20121018 15 45 35 18-oct-2012 03:31 18-oct-2012 16:41
20121018 16 45 41 18-oct-2012 15:31 18-oct-2012 16:41
20121018 17 45 19 18-oct-2012 17:41 18-oct-2012 18:06
20121018 18 45 6 18-oct-2012 17:41 18-oct-2012 18:06
20121018 19 45 15 18-oct-2012 19:16 18-oct-2012 19:41
20121018 20 45 9 18-oct-2012 20:51 18-oct-2012 23:16
20121018 21 45 60 18-oct-2012 20:51 18-oct-2012 23:16
20121018 22 45 60 18-oct-2012 20:51 18-oct-2012 23:16
20121018 23 45 16 18-oct-2012 20:51 18-oct-2012 23:16
20121019 0 45 50 19-oct-2012 00:01 19-oct-2012 00:51
39 rows selected.
一些注意事项:首先我计算了每行所需的时间。
SQL> select rownum id, "SensorKey" s_key, cast("StartTime" as date) s_time, cast("EndTime" as date) e_time,
2 ((trunc(cast("EndTime" as date) , 'hh24') -trunc(cast("StartTime" as date), 'hh24')) *24)+1 hours
3 from table1;
ID S_KEY S_TIME E_TIME HOURS
---------- ---------- ----------------- ----------------- ----------
1 45 17-oct-2012 08:31 17-oct-2012 10:21 3
这个“HOURS”列将驱动模型子句告诉它每个源行要生成多少行。rownum ID 只是用于唯一键(因为其他数据似乎不能保证唯一性)。
我在 ID 上进行了分区
model partition by (id as key)
这意味着我们将每一行作为单独的处理。
在度量中,我们列出了我们将要使用的领域(计算或只是输出)。
measures (s_key, s_time, e_time,
cast(null as number(2,0)) duration, hours,
cast(null as number(2)) thehour,
cast(null as date) block_start,
cast(null as date) block_end)
这些cast()
列只是不在原始集合中的列,而是我们将在进行时计算的列。
duration
将保存分钟,thehour
将显示小时数,blocks
并将保存当前小时适合的小时槽。
规则是我们完成所有逻辑的地方..so:
rules (block_start[for f from 0 to hours[0]-1 increment 1] = trunc(s_time[0] + (cv(f)/24), 'hh24'),
"for f from 0 to hours[0]-1 increment 1"
表示我们正在根据HOURS
列生成行(第一行为 3)。
块开始将设置为17-oct-2012 08:00
第一行和块结束09:00
(在第 2 行,我们将它们提高一个小时,依此类推。
s_key[any] = s_key[0],
s_time[any] = s_time[0],
e_time[any] = e_time[0],
以上三项简单地按原样复制到输出集。ANY 关键字表示匹配所有行(我们可以在这里放置“for f..”逻辑,但 ANY 更简洁。
持续时间是用 case 语句计算的
case
when cv(f) = 0
then (least(block_end[cv(f)],e_time[0]) - s_time[0]) * 24*60
when cv(f) = hours[0]-1
then (e_time[0] - block_start[cv(f)] ) * 24*60
else (block_end[cv(f)] - block_start[cv(f)] ) * 24*60
end
即cv(f) = 0
表示第一个输出行(cv
bieng 一个访问“当前值”的函数,在这种情况下,是F
变量。所以第一行,我们取块结束(17-oct-2012 09:00
) - 开始时间(17-oct-2012 08:31
)并在几分钟内得到它(29分钟). 对于结束行,我们再次取结束时间 ( 17-oct-2012 10:21
) - 块开始 ( 17-oct-2012 10:00
) = 21 分钟之间的所有行,我们只是从块开始中减去块结束(即 60 分钟)
这会给我们的输出为:
TimeKey Hour SensorKey Duration StartTime EndTime
-------- ---------- ---------- ---------- ----------------- -----------------
20121017 8 45 29 17-oct-2012 08:31 17-oct-2012 10:21
20121017 9 45 60 17-oct-2012 08:31 17-oct-2012 10:21
20121017 10 45 21 17-oct-2012 08:31 17-oct-2012 10:21
20121017 10 45 25 17-oct-2012 10:26 17-oct-2012 10:51
...etc..
但是你说对“10”行进行分组,所以现在它是一个简单的分组来完成这个:
select to_char(block_start, 'yyyymmdd') "TimeKey",
thehour "Hour", s_key "SensorKey",
sum(duration) "Duration", min(s_time) "StartTime", max(e_time) "EndTime"
from (..our model query...)
group by block_start, thehour, s_key;