我的 ERP 数据库中有一个表格,其中包含有关某些事件的数据。它有开始日期、结束日期和一列显示事件是否是前一个事件的延续(sequential_id 引用 unique_id)。举个例子:
unique_id | 开始日期 | 结束日期 | sequential_id |
---|---|---|---|
001 | 2021-01-01 | 2021-01-15 | |
002 | 2021-02-01 | 2021-02-16 | 001 |
003 | 2021-03-01 | 2021-03-17 | 002 |
004 | 2021-03-10 | 2021-03-11 | |
005 | 2021-03-19 |
在上面的示例中,第 001、002 和 003 行都是同一事件的一部分,而 004/005 是唯一事件,没有序列。如何以输出如下所示的方式对数据进行分组:
origin_id | 开始日期 | 结束日期 |
---|---|---|
001 | 2021-01-01 | 2021-03-17 |
004 | 2021-03-10 | 2021-03-11 |
005 | 2021-03-19 |
我尝试过使用 group by,但由于sequential_id 是自动增量的,它没有用。
提前致谢。
答案 0 :(得分:4)
您可以使用现代 match_recognize
,这是此类任务的最佳解决方案:
Pattern Recognition With MATCH_RECOGNIZE
select *
from t
match_recognize(
measures
first(unique_id) start_unique_id,
first(start_date) start_date,
last(end_date) end_date
pattern (strt nxt*)
define nxt as sequential_id=prev(unique_id)
);
答案 1 :(得分:2)
您可以为此使用分层查询:
<块引用>with a (unique_id, start_date, end_date, sequential_id) as (
select '001', date '2021-01-01', date '2021-01-15', null from dual union all
select '002', date '2021-02-01', date '2021-02-16', '001' from dual union all
select '003', date '2021-03-01', date '2021-03-17', '002' from dual union all
select '004', date '2021-03-10', date '2021-03-11', null from dual union all
select '005', date '2021-03-19', null, null from dual
)
, b as (
select
connect_by_root(unique_id) as unique_id
, connect_by_root(start_date) as start_date
, end_date
, connect_by_isleaf as l
from a
start with sequential_id is null
connect by prior unique_id = sequential_id
)
select
unique_id
, start_date
, end_date
from b
where l = 1
order by 1 asc
UNIQUE_ID | START_DATE | END_DATE :-------- | :--------- | :-------- 001 | 01-JAN-21 | 17-MAR-21 004 | 10-MAR-21 | 11-MAR-21 005 | 19-MAR-21 | null
db<>fiddle here
答案 2 :(得分:1)
这是一个图遍历问题,因此您可以使用递归 CTE:
with cte (unique_id, start_date, end_date, start_unique_id) as (
select unique_id, start_date, end_date, unique_id
from t
where not exists (select 1 from t t2 where t.sequential_id = t2.unique_id)
union all
select t.unique_id, t.start_date, t.end_date, cte.start_unique_id
from cte join
t
on cte.unique_id = t.sequential_id
)
select start_unique_id, min(start_date), max(end_date)
from cte
group by start_Unique_id;
Here 是一个 db<>fiddle。