Categorize rows as first, last or in between

casegroup byoracleoracle-12c

enter image description here

I have a table called road_events.

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

insert into road_events (event_id,road_id,event_type,lifecycle_number) values (1,100,'RECONSTRUCTION',1);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (2,100,'RECONSTRUCTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (3,100,'INSPECTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (4,100,'INSPECTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (5,100,'INSPECTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (6,100,'INSPECTION',2);

insert into road_events (event_id,road_id,event_type,lifecycle_number) values (7,200,'INSPECTION',0);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (8,200,'RECONSTRUCTION',1);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (9,200,'INSPECTION',1);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (10,200,'INSPECTION',1);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (11,200,'RECONSTRUCTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (12,200,'INSPECTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (13,200,'INSPECTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (14,200,'INSPECTION',2);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (15,200,'RECONSTRUCTION',3);

insert into road_events (event_id,road_id,event_type,lifecycle_number) values (16,300,'RECONSTRUCTION',1);

insert into road_events (event_id,road_id,event_type,lifecycle_number) values (17,400,'INSPECTION',0);

insert into road_events (event_id,road_id,event_type,lifecycle_number) values (18,500,'RECONSTRUCTION',1);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (19,500,'RECONSTRUCTION',2);

insert into road_events (event_id,road_id,event_type,lifecycle_number) values (20,600,'INSPECTION',0);
insert into road_events (event_id,road_id,event_type,lifecycle_number) values (21,600,'INSPECTION',0);

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

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

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

        16        300 RECONSTRUCTION                 1

        17        400 INSPECTION                     0

        18        500 RECONSTRUCTION                 1
        19        500 RECONSTRUCTION                 2

        20        600 INSPECTION                     0
        21        600 INSPECTION                     0

For each road, I would like to categorize the rows in each lifecycle with a lifecycle_name (in this order):

  1. The rows in the last(max) lifecycle would be called current lifecycle
  2. The rows in the first(min) lifecycle would be called original lifecycle (if applicable)
  3. Any others would be called past lifecycle (if applicable)

It would look like this:

+----------+---------+----------------+------------------+--------------------+
| EVENT_ID | ROAD_ID |   EVENT_TYPE   | LIFECYCLE_NUMBER |   LIFECYCLE_NAME   |
+----------+---------+----------------+------------------+--------------------+
|        1 |     100 | RECONSTRUCTION |                1 | ORIGINAL LIFECYCLE |
|        2 |     100 | RECONSTRUCTION |                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 | RECONSTRUCTION |                1 | PAST LIFECYCLE     |
|        9 |     200 | INSPECTION     |                1 | PAST LIFECYCLE     |
|       10 |     200 | INSPECTION     |                1 | PAST LIFECYCLE     |
|       11 |     200 | RECONSTRUCTION |                2 | PAST LIFECYCLE     |
|       12 |     200 | INSPECTION     |                2 | PAST LIFECYCLE     |
|       13 |     200 | INSPECTION     |                2 | PAST LIFECYCLE     |
|       14 |     200 | INSPECTION     |                2 | PAST LIFECYCLE     |
|       15 |     200 | RECONSTRUCTION |                3 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+
|       16 |     300 | RECONSTRUCTION |                1 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+
|       17 |     400 | INSPECTION     |                0 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+
|       18 |     500 | RECONSTRUCTION |                1 | ORIGINAL LIFECYCLE |
|       19 |     500 | RECONSTRUCTION |                2 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+
|       20 |     600 | INSPECTION     |                0 | CURRENT LIFECYCLE  |
|       21 |     600 | INSPECTION     |                0 | CURRENT LIFECYCLE  |
+----------+---------+----------------+------------------+--------------------+

Is there a way to succinctly categorize the rows into current lifecycle, original lifecycle, and past lifecycle, where applicable?

I can think of some lengthy/cumbersome ways to do it with case statements and subqueries, but I'm looking for something a bit more elegant than that.

Update:

  1. I've updated the question with a few more scenarios (roads 300-600). Credit goes to @markp for thinking of this.

  2. @markp also highlighted that current lifecycle trumps original lifecycle.

Best Answer

You can use two window functions, min() and max() with the same window, over the partition by road_id:

select  event_id,
        road_id,
        event_type,
        lifecycle_number,
        case lifecycle_number
            when max(lifecycle_number) over (partition by road_id)
                then 'CURRENT LIFECYCLE'
            when min(lifecycle_number) over (partition by road_id)  
                then 'ORIGINAL LIFECYCLE'
                else 'PAST LIFECYCLE'
        end as LIFECYCLE_NAME
from    road_events re
order by event_id;

You could also use first_value() and last_value() window functions.

Test at dbfiddle.uk