将行分类为第一行、最后一行或中间行
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
(按此顺序)对每个生命周期中的行进行分类:
- 最后(最大)个生命周期中的行将被称为
current lifecycle
如果每个生命周期超过 1 行,则:
- 第一个(分钟)生命周期中的行将被称为
original lifecycle
(如果适用)
- 任何其他人将被称为
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;
您可以使用 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 发现了早期版本中的错误 - 有关详细信息,请参阅此答案下方的评论。
我有一个叫 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
(按此顺序)对每个生命周期中的行进行分类:
- 最后(最大)个生命周期中的行将被称为
current lifecycle
如果每个生命周期超过 1 行,则:
- 第一个(分钟)生命周期中的行将被称为
original lifecycle
(如果适用) - 任何其他人将被称为
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;
您可以使用 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 发现了早期版本中的错误 - 有关详细信息,请参阅此答案下方的评论。