将记录分组到特定条件并查找最大值

Dba*_*Dba 6 sql oracle oracle11g gaps-and-islands

我有一个veh_speed与领域表vid,date_time,speed,status.我的目标是获得速度大于30的车辆的持续时间(start_date_timeend_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)

我希望我明白我的问题.

提前致谢.

Ale*_*ole 5

您可以使用分析函数将记录分组为速度为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)

SQL小提琴.