Dba*_*Dba 6 sql oracle oracle11g gaps-and-islands
我有一个veh_speed与领域表vid,date_time,speed,status.我的目标是获得速度大于30的车辆的持续时间(start_date_time和end_date_time).目前我正在使用生成报告PL/SQL.是否可以使用SQL.如果可以在范围之间获得max_speed也会很棒.
我的表格如下:
VID START_DATE_TIME SPEED STATUS
--- ------------------- ----- ------
1 15/01/2014 10:00:05 0 N
1 15/01/2014 10:00:10 10 Y
1 15/01/2014 10:00:15 30 Y
1 15/01/2014 10:00:20 35 Y
1 15/01/2014 10:00:25 45 Y
1 15/01/2014 10:00:27 10 Y
1 15/01/2014 10:00:29 0 Y
1 15/01/2014 10:00:30 20 Y
1 15/01/2014 10:00:35 32 Y
1 15/01/2014 10:00:40 33 Y
1 15/01/2014 10:00:45 35 Y
1 15/01/2014 10:00:50 38 Y
1 15/01/2014 10:00:55 10 Y
Run Code Online (Sandbox Code Playgroud)
我想得到以下输出:
VID START_DATE_TIME END_DATE_TIME MAX_SPEED
--- --------------- ------------- ---------
1 15/01/2014 10:00:15 15/01/2014 10:00:25 45
1 15/01/2014 10:00:35 15/01/2014 10:00:50 38
Run Code Online (Sandbox Code Playgroud)
这是表创建脚本:
CREATE TABLE veh_speed(vid NUMBER(3),
date_time DATE,
speed NUMBER(3),
status CHAR(1));
INSERT ALL
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:05', 'dd/mm/yyyy hh24:mi:ss'), 0, 'N')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:10', 'dd/mm/yyyy hh24:mi:ss'), 10, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:15', 'dd/mm/yyyy hh24:mi:ss'), 30, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:20', 'dd/mm/yyyy hh24:mi:ss'), 35, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:25', 'dd/mm/yyyy hh24:mi:ss'), 45, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:27', 'dd/mm/yyyy hh24:mi:ss'), 10, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:29', 'dd/mm/yyyy hh24:mi:ss'), 0, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:30', 'dd/mm/yyyy hh24:mi:ss'), 20, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:35', 'dd/mm/yyyy hh24:mi:ss'), 32, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:40', 'dd/mm/yyyy hh24:mi:ss'), 33, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:45', 'dd/mm/yyyy hh24:mi:ss'), 35, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:50', 'dd/mm/yyyy hh24:mi:ss'), 38, 'Y')
INTO veh_speed VALUES(1, to_date('15/01/2014 10:00:55', 'dd/mm/yyyy hh24:mi:ss'), 10, 'Y')
SELECT * FROM dual;
Run Code Online (Sandbox Code Playgroud)
我希望我明白我的问题.
提前致谢.
您可以使用分析函数将记录分组为速度为30或更高的块:
select vid, date_time, speed, status,
case when speed >= 30 then 30 else 0 end as speed_limit,
row_number() over (partition by vid order by date_time)
- row_number() over (
partition by vid, case when speed >= 30 then 30 else 0 end
order by date_time) as chain
from veh_speed;
VID DATE_TIME SPEED STATUS SPEED_LIMIT CHAIN
---------- ------------------- ---------- ------ ----------- ----------
1 15/01/2014 10:00:05 0 N 0 0
1 15/01/2014 10:00:10 10 Y 0 0
1 15/01/2014 10:00:15 30 Y 30 2
1 15/01/2014 10:00:20 35 Y 30 2
1 15/01/2014 10:00:25 45 Y 30 2
1 15/01/2014 10:00:27 10 Y 0 3
1 15/01/2014 10:00:29 0 Y 0 3
1 15/01/2014 10:00:30 20 Y 0 3
1 15/01/2014 10:00:35 32 Y 30 5
1 15/01/2014 10:00:40 33 Y 30 5
1 15/01/2014 10:00:45 35 Y 30 5
1 15/01/2014 10:00:50 38 Y 30 5
1 15/01/2014 10:00:55 10 Y 0 7
Run Code Online (Sandbox Code Playgroud)
我不能因为使用两次row_number()调用来生成记录链而得到奖励,不幸的是,我在某处(可能在这里)选择了它.实际值chain无关紧要,只是它们vid在符合条件的连续记录块中的每个记录中都是唯一的.
您只对"速度限制"为30的相关记录链感兴趣(这可能很容易成为Y/N标志或其他),因此您可以使用它并过滤掉链的速度为少于30; 然后使用普通的聚合函数来获得你想要的:
select vid,
min(date_time) as start_date_time,
max(date_time) as end_date_time,
max(speed) as max_speed
from (
select vid, date_time, speed, status,
case when speed >= 30 then 30 else 0 end as speed_limit,
row_number() over (partition by vid order by date_time)
- row_number() over (
partition by vid, case when speed >= 30 then 30 else 0 end
order by date_time) as chain
from veh_speed
)
where speed_limit = 30
group by vid, chain
order by vid, start_date_time;
VID START_DATE_TIME END_DATE_TIME MAX_SPEED
---------- ------------------- ------------------- ----------
1 15/01/2014 10:00:15 15/01/2014 10:00:25 45
1 15/01/2014 10:00:35 15/01/2014 10:00:50 38
Run Code Online (Sandbox Code Playgroud)