Oracle和MS SQL Query根据日期时间从一行中获取多行

时间:2013-01-29 21:12:36

标签: sql sql-server oracle tsql

您好我收到的Oracle Query返回:

SQLFIDDLEExample

   SensorKey    StartTime   EndTime
    45  2012.10.17 08:31    2012.10.17 10:21
    45  2012.10.17 10:26    2012.10.17 10:51
    45  2012.10.17 12:21    2012.10.17 12:26
    45  2012.10.17 12:41    2012.10.17 13:41
    45  2012.10.17 13:51    2012.10.17 14:46
    45  2012.10.17 15:11    2012.10.17 15:16
    45  2012.10.17 15:46    2012.10.17 16:21
    45  2012.10.17 18:51    2012.10.17 18:56
    45  2012.10.17 19:11    2012.10.17 19:56
    45  2012.10.17 20:26    2012.10.17 21:11
    45  2012.10.17 22:16    2012.10.17 22:21
    45  2012.10.17 22:26    2012.10.17 22:56
    45  2012.10.17 23:36    2012.10.18 01:46
    45  2012.10.18 02:16    2012.10.18 02:56
    45  2012.10.18 03:31    2012.10.18 15:06
    45  2012.10.18 15:31    2012.10.18 16:41
    45  2012.10.18 17:41    2012.10.18 18:06
    45  2012.10.18 19:16    2012.10.18 19:26
    45  2012.10.18 19:36    2012.10.18 19:41
    45  2012.10.18 20:51    2012.10.18 23:16
    45  2012.10.19 00:01    2012.10.19 00:51

我需要获得所有数据的结果。第一行示例:

   SensorKey    StartTime          EndTime
    45         2012.10.17 08:31 2012.10.17 10:21

像这样,依此类推其他行:

TimeKey    Hour  SensorKey  Duration    StartTime   EndTime
20121017    8         45         29     2012.10.17 08:31    2012.10.17 10:21
20121017    9         45         60     2012.10.17 08:31    2012.10.17 10:21
20121017    10        45         21     2012.10.17 08:31    2012.10.17 10:21

规则:

  1. 复制一行多次小时重叠,例如第一行重叠8,9,10小时。

  2. Timekey =来自StartTime的日期格式YYYYMMDD

    Hour =来自StartTime的小时格式为H 24H

    Duration小时持续时间(分钟)。

  3. 如果一小时内有多行,则必须对两个第一行进行分组示例:

    TimeKey    Hour        SensorKey    Duration    StartTime            EndTime
    20121017    8          45           29          2012.10.17 08:31    2012.10.17 10:21
    20121017    9          45           60          2012.10.17 08:31    2012.10.17 10:21
    20121017    10         45           46          2012.10.17 08:31    2012.10.17 10:21
    

1 个答案:

答案 0 :(得分:1)

对于Oracle,一种方法是Model子句(因为我们正在组成行,model子句可以为我们这样做)。

一些事情。你似乎只想要数据到分钟,所以使用日期与时间戳是有意义的。其次,我要避免在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”列将驱动model子句,告诉它每个源行要生成多少行。 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将保留当前小时所适合的小时位。

规则是我们所有逻辑完成的地方。所以:

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 
  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;