将行分为第一个,最后一个或两者之间

时间:2017-11-24 17:57:01

标签: sql oracle case categories oracle12c

docs

我有一张名为road_events的表。

  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
  2. 如果每个生命周期有超过1行,则:

    1. 第一个(最小)生命周期中的行将被称为original lifecycle(如果适用)
    2. 任何其他人都会被称为past lifecycle(如果适用)
    3. 看起来像这样:

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

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

      我可以用case语句和子查询来思考一些冗长/繁琐的方法,但我正在寻找比这更优雅的东西。

2 个答案:

答案 0 :(得分:1)

没有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

答案 1 :(得分:1)

您可以使用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在早期版本中发现错误 - 请参阅下面的评论以获取详细信息。