将行分类为第一行、最后一行或中间行

Categorize rows as first, last or in between

我有一个叫 road_events 的 table。

  create table infrastr.road_events 
   (
    event_id number(5,0),
    road_id number(5,0),
    event_type nvarchar2(50),
    lifecycle_number number(5,0)
   );

insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (1,100,'CONSTRUCTION  ',1);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (2,100,'CONSTRUCTION  ',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (3,100,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (4,100,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (5,100,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (6,100,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (7,200,'INSPECTION',0);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (8,200,'CONSTRUCTION  ',1);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (9,200,'INSPECTION',1);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (10,200,'INSPECTION',1);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (11,200,'CONSTRUCTION  ',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (12,200,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (13,200,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (14,200,'INSPECTION',2);
insert into infrastr.road_events (event_id,road_id,event_type,lifecycle_number) values (15,200,'CONSTRUCTION  ',3);

select
    event_id,
    road_id,
    substr(event_type,0,15) as event_type,
    lifecycle_number
from
    infrastr.road_events
order by
    event_id

  EVENT_ID    ROAD_ID EVENT_TYPE      LIFECYCLE_NUMBER
---------- ---------- --------------- ----------------
         1        100 CONSTRUCTION                   1
         2        100 CONSTRUCTION                   2
         3        100 INSPECTION                     2
         4        100 INSPECTION                     2
         5        100 INSPECTION                     2
         6        100 INSPECTION                     2

         7        200 INSPECTION                     0
         8        200 CONSTRUCTION                   1
         9        200 INSPECTION                     1
        10        200 INSPECTION                     1
        11        200 CONSTRUCTION                   2
        12        200 INSPECTION                     2
        13        200 INSPECTION                     2
        14        200 INSPECTION                     2
        15        200 CONSTRUCTION                   3

对于每条道路,我想用lifecycle_name(按此顺序)对每个生命周期中的行进行分类:

  1. 最后(最大)个生命周期中的行将被称为 current lifecycle

如果每个生命周期超过 1 行,则:

  1. 第一个(分钟)生命周期中的行将被称为 original lifecycle(如果适用)
  2. 任何其他人将被称为 past lifecycle(如果适用)

看起来像这样:

+----------+---------+----------------+------------------+--------------------+
| EVENT_ID | ROAD_ID |   EVENT_TYPE   | LIFECYCLE_NUMBER |   LIFECYCLE_NAME   |
+----------+---------+----------------+------------------+--------------------+
|        1 |     100 | CONSTRUCTION   |                1 | ORIGINAL LIFECYCLE |
|        2 |     100 | CONSTRUCTION   |                2 | CURRENT LIFECYCLE  |
|        3 |     100 | INSPECTION     |                2 | CURRENT LIFECYCLE  |
|        4 |     100 | INSPECTION     |                2 | CURRENT LIFECYCLE  |
|        5 |     100 | INSPECTION     |                2 | CURRENT LIFECYCLE  |
|        6 |     100 | INSPECTION     |                2 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+
|        7 |     200 | INSPECTION     |                0 | ORIGINAL LIFECYCLE |
|        8 |     200 | CONSTRUCTION   |                1 | PAST LIFECYCLE     |
|        9 |     200 | INSPECTION     |                1 | PAST LIFECYCLE     |
|       10 |     200 | INSPECTION     |                1 | PAST LIFECYCLE     |
|       11 |     200 | CONSTRUCTION   |                2 | PAST LIFECYCLE     |
|       12 |     200 | INSPECTION     |                2 | PAST LIFECYCLE     |
|       13 |     200 | INSPECTION     |                2 | PAST LIFECYCLE     |
|       14 |     200 | INSPECTION     |                2 | PAST LIFECYCLE     |
|       15 |     200 | CONSTRUCTION   |                3 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+

有没有办法按照描述对行进行简洁分类?

我可以想到一些 lengthy/cumbersome 方法来使用 case 语句和子查询,但我正在寻找比这更优雅的东西。

另一个没有 CASE 语句的选项是使用 decode.

with EVENTS
     AS (SELECT event_id,
                road_id,
                SUBSTR(event_type, 0, 15)  AS event_type,
                lifecycle_number,
                MIN(lifecycle_number)
                  over (
                    PARTITION BY road_id ) min_val,
                MAX(lifecycle_number)
                  over (
                    PARTITION BY road_id ) max_val
         FROM   road_events)
SELECT event_id,
       road_id,
       event_type,
       lifecycle_number,
       DECODE(lifecycle_number, min_val, 'ORIGINAL LIFECYCLE',
                                max_val, 'CURRENT LIFECYCLE',
                                'PAST LIFECYCLE') LIFECYCLE_NAME
FROM   EVENTS
ORDER  BY event_id;  

SQL Fiddle

您可以使用 match_recognize() 子句来获得简洁高效的解决方案:

select event_id, road_id, event_type, lifecycle_number, lifecycle_name
from   road_events
match_recognize(
  partition by road_id
  order     by lifecycle_number
  measures  case classifier() when 'A' then 'ORIGINAL LIFECYCLE'
                              when 'B' then 'PAST LIFECYCLE'
                              else          'CURRENT LIFECYCLE'
            end  as lifecycle_name
  all rows per match
  pattern   ( ^ a+ b* c d* $ )
  define    a as lifecycle_number  = first(lifecycle_number),
            c as lifecycle_number != prev(lifecycle_number),
            d as lifecycle_number  = prev(lifecycle_number)
);

注意:感谢@MT0 发现了早期版本中的错误 - 有关详细信息,请参阅此答案下方的评论。