按个人时间范围分组

时间:2016-06-29 13:56:37

标签: sql oracle select group-by

我想按个别时间范围对表格的行进行分组。

作为一个例子,让我们想象一下我们在机场有一份出发名单:

| Departure           | Flight | Destination |
| 2016-06-01 10:12:00 | LH1234 | New York    |
| 2016-06-02 14:23:00 | LH1235 | Berlin      |
| 2016-06-02 14:30:00 | LH1236 | Tokio       |
| 2016-06-03 18:45:00 | LH1237 | Belgrad     |
| 2016-06-04 04:10:00 | LH1237 | Rio         |
| 2016-06-04 06:20:00 | LH1237 | Paris       |

我可以使用以下查询轻松地按整小时(天,周,...)对数据进行分组:

select to_char(departure, 'HH24') as "full hour", count(*) as "number flights"
from departures
group by to_char(departure, 'HH24')

这应该产生下表。

| full hour | number flights |
| 04        | 1              |
| 06        | 1              |
| 10        | 1              |
| 14        | 2              |
| 18        | 1              |

现在我的问题:是否有一种优雅的方式(或最佳实践)按个别时间范围对数据进行分组。 我正在寻找的结果如下:

| time frame                           | number flights |
| 2016-05-31 22:00 - 2016-06-01 06:00  | 0              |
| 2016-06-01 06:00 - 2016-06-01 14:00  | 1              |
| 2016-06-01 14:00 - 2016-06-01 22:00  | 0              |
| 2016-06-01 22:00 - 2016-06-02 06:00  | 0              |
| 2016-06-02 06:00 - 2016-06-02 14:00  | 0              |
| 2016-06-02 14:00 - 2016-06-02 22:00  | 2              |
| 2016-06-02 22:00 - 2016-06-03 06:00  | 0              |
| 2016-06-03 06:00 - 2016-06-03 14:00  | 0              |
| 2016-06-03 14:00 - 2016-06-03 22:00  | 1              |
| 2016-06-03 22:00 - 2016-06-04 06:00  | 1              |
| 2016-06-04 06:00 - 2016-06-04 14:00  | 1              |
| 2016-06-04 14:00 - 2016-06-04 22:00  | 0              |
| 2016-06-04 22:00 - 2016-06-05 06:00  | 0              |

(有0个航班的行并不相关。它们只是为了更好地显示问题。)

提前感谢您的回答。 :-) 彼得

2 个答案:

答案 0 :(得分:1)

由于您的小组从22:00开始,之后是8小时的倍数,因此您可以使用sum(SomeColumn) over (Order By SomeColumn) 和2小时的偏移量来获得按天分组的结果。

然后,您可以计算出发时间的第三天,也可以按以下方式分组:

TRUNC()

答案 1 :(得分:1)

这样的事情应该有效。请注意两个输入变量first_timetimespantimespan是你想要的任何东西(我用8/24的形式写了八个小时;如果你把timespan变成一个绑定变量作为用HOURS表示的数字,你需要划分到24)。由于我编写公式的方式,first_time没有要求,除了它应该是你的边界日期/时间之一;它甚至可能在将来,它不会改变结果。它也可以变成一个绑定变量,然后你可以决定你希望它以什么样的格式提供给查询。

with timetable (departure, flight, destination) as (
       select to_date('2016-06-01 10:12:00', 'yyyy-mm-dd hh24:mi:ss'), 'LH1234', 'New York' 
         from dual      union all
       select to_date('2016-06-02 14:23:00', 'yyyy-mm-dd hh24:mi:ss'), 'LH1235', 'Berlin'   
         from dual      union all
       select to_date('2016-06-02 14:30:00', 'yyyy-mm-dd hh24:mi:ss'), 'LH1236', 'Tokyo'    
         from dual      union all
       select to_date('2016-06-03 18:45:00', 'yyyy-mm-dd hh24:mi:ss'), 'LH1237', 'Belgrad'  
         from dual      union all
       select to_date('2016-06-04 04:10:00', 'yyyy-mm-dd hh24:mi:ss'), 'LH1237', 'Rio'
         from dual      union all
       select to_date('2016-06-04 06:20:00', 'yyyy-mm-dd hh24:mi:ss'), 'LH1237', 'Paris'
         from dual
     ),
     input_values (first_time, timespan) as (
       select to_date('2010-01-01 06:00:00', 'yyyy-mm-dd hh24:mi:ss'), 8/24 from dual
     ),
     prep (adj_departure, flight, destination) as (
       select first_time + timespan * floor((departure - first_time) / timespan), 
              flight, destination
       from   timetable, input_values
     )
select to_char(adj_departure, 'yyyy-mm-dd hh24:mi:ss') || ' - ' ||
             to_char(adj_departure + timespan, 'yyyy-mm-dd hh24:mi:ss') as time_interval,
       count(*) as ct
from   prep, input_values
group by adj_departure, timespan
order by adj_departure
;

<强>输出

TIME_INTERVAL                                     CT
----------------------------------------- ----------
2016-06-01 06:00:00 - 2016-06-01 14:00:00          1
2016-06-02 14:00:00 - 2016-06-02 22:00:00          2
2016-06-03 14:00:00 - 2016-06-03 22:00:00          1
2016-06-03 22:00:00 - 2016-06-04 06:00:00          1
2016-06-04 06:00:00 - 2016-06-04 14:00:00          1