使用match_recognize 的解决方案(自数据库版本 12.1 起可用)
为测试设置数据:
alter session set nls_date_format='mm/dd/yyyy';
create table my_table (emp_id, eff_dt, dept_id) as
select 100, to_date('01/01/2015'), 'ENGINEERING' from dual union all
select 100, to_date('01/01/2016'), 'ENGINEERING' from dual union all
select 100, to_date('01/01/2017'), 'ENGINEERING' from dual union all
select 100, to_date('01/01/2018'), 'FINANCE' from dual union all
select 100, to_date('01/01/2019'), 'FINANCE' from dual union all
select 100, to_date('01/01/2020'), 'ENGINEERING' from dual union all
select 100, to_date('01/01/2021'), 'ENGINEERING' from dual
;
查询和输出:
select emp_id, eff_dt, dept_id
from my_table
match_recognize(
partition by emp_id
order by eff_dt
all rows per match
pattern ( a {- b* -} )
define b as dept_id = a.dept_id
);
EMP_ID EFF_DT DEPT_ID
---------- ---------- -----------
100 01/01/2015 ENGINEERING
100 01/01/2018 FINANCE
100 01/01/2020 ENGINEERING
简要说明:
match_recognize 子句按emp_id 对输入行进行分区,并按eff_dt 对其进行排序。然后它进一步将每个分区内的行按照日期顺序划分为“匹配项”,匹配pattern 子句中给出的模式。这是一个 a 行,后跟 0 个或多个 b 行,其中定义了 b(在 define 子句中)要求 dept_id 与匹配的第一行相同.行没有条件成为a 行;任何行,如果它不能被归类为b,将被归类为a(它将开始一个新的匹配!)
返回匹配中的“所有”行,但 pattern 子句中的 {- -} 中包含的行除外。即:返回每个匹配项中的a 行(第一行),而不返回b 行。完全按照规定。
编辑
对于 Oracle 11.2 或更低版本,以及尚不支持 match_recognize 的数据库产品(Oracle 除外),这可以通过绝大多数数据库支持的分析功能来完成。
以下版本与match_recognize 解决方案几乎完全相同:
select emp_id, eff_dt, dept_id
from (
select emp_id, eff_dt, dept_id,
case when lag(dept_id) over (partition by emp_id
order by eff_dt) = dept_id
then 'B' else 'A' end as classifier
from my_table
)
where classifier = 'A'
;