oracle 查询以识别一些基于重叠日期期间的条件

oracle query to identify some condition based overlapping date periods

我有一个数据集,其日期在一个缓慢变化的维度 table 中重叠。我正在尝试提出一个查询,以根据少数条件找出具有重叠日期范围的人。

例如

PERSON_ID,RELATION_ID,RELATION_NAME,START_DT,  END_DT, ACTIVE_IND,LATEST_ROW
STEVE     -1          NONE          7/26/2018  10/24/2018 Y          N
STEVE     111         STUDENT       8/8/2018   10/22/2018 Y          N
STEVE     111         STUDENT       10/23/2018 12/31/4712 Y          Y
STEVE     -1          NONE          10/25/2018 2/7/2019   Y          N
STEVE     222         Manager       8/9/2018   12/31/4712 Y          Y
BOB       333         ASSOCIATE     8/9/2018   12/31/4712 Y          Y
BOB       666         TEACHER       8/10/2018  12/31/4712 Y          Y
Dave      555         Director      8/9/2018   12/31/4712 Y          Y

我想找到具有重叠日期范围的 person_ids,仅当 relationship_id 中至少有一个为 -1 时。例如,BOB 在重叠时期既是同事又是老师。一个人有两个角色是可以的。但是,我想找出所有日期重叠的人,这些人涉及 "None" 关系和其他一些角色。例子:史蒂夫。

你能给我一些关于如何提出查询的建议吗

Oracle 设置:

CREATE TABLE table_name ( PERSON_ID, RELATION_ID, RELATION_NAME, START_DT, END_DT, ACTIVE_IND,LATEST_ROW ) AS
SELECT 'STEVE',  -1, 'NONE',      DATE '2018-07-26', DATE '2018-10-24', 'Y', 'N' FROM DUAL UNION ALL
SELECT 'STEVE', 111, 'STUDENT',   DATE '2018-08-08', DATE '2018-10-22', 'Y', 'N' FROM DUAL UNION ALL
SELECT 'STEVE', 111, 'STUDENT',   DATE '2018-10-23', DATE '4712-12-31', 'Y', 'Y' FROM DUAL UNION ALL
SELECT 'STEVE',  -1, 'NONE',      DATE '2018-10-25', DATE '2019-02-07', 'Y', 'N' FROM DUAL UNION ALL
SELECT 'STEVE', 222, 'Manager',   DATE '2018-08-09', DATE '4712-12-31', 'Y', 'Y' FROM DUAL UNION ALL
SELECT 'BOB',   333, 'ASSOCIATE', DATE '2018-08-09', DATE '4712-12-31', 'Y', 'Y' FROM DUAL UNION ALL
SELECT 'BOB',   666, 'TEACHER',   DATE '2018-08-10', DATE '4712-12-31', 'Y', 'Y' FROM DUAL UNION ALL
SELECT 'Dave',  555, 'Director',  DATE '2018-08-09', DATE '4712-12-31', 'Y', 'Y' FROM DUAL;

查询:

SELECT DISTINCT
       PERSON_ID
FROM   table_name t
WHERE  RELATION_ID = -1
AND    EXISTS (
  SELECT 1
  FROM   table_name o
  WHERE  t.person_id = o.person_id
  AND    t.end_dt    > o.start_dt
  AND    t.start_dt  < o.end_dt
  AND    o.relation_id <> -1
)

输出:

| PERSON_ID |
| :-------- |
| STEVE     |

db<>fiddle here

用上面的模式识别拍了一张照片,它显示了所有相互重叠的行。在这种情况下,一行在 RELATION_IDs = -1 中重叠了两次,因此它在两种重叠情况下都显示同一行,并且查询将其标记为 overlap_num 1 和 2.

with t (PERSON_ID,RELATION_ID,RELATION_NAME,START_DT,  END_DT, ACTIVE_IND,LATEST_ROW) as (
select 'STEVE',     -1,          'NONE',        to_date('7/26/2018', 'MM/DD/YYYY'), to_date('10/24/2018', 'MM/DD/YYYY'), 'Y', 'N' from dual union all
select 'STEVE',     111,         'STUDENT',      to_date('8/8/2018', 'MM/DD/YYYY'), to_date('10/22/2018', 'MM/DD/YYYY'), 'Y', 'N' from dual union all
select 'STEVE',     111,         'STUDENT',      to_date('10/23/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
select 'STEVE',     -1,          'NONE',         to_date('10/25/2018', 'MM/DD/YYYY'), to_date('2/7/2019', 'MM/DD/YYYY'),   'Y', 'N' from dual union all
select 'STEVE',     222,         'Manager',      to_date('8/9/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
select 'BOB',       333,         'ASSOCIATE',    to_date('8/9/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
select 'BOB',       666,         'TEACHER',      to_date('8/10/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
select 'Dave',      555,         'Director',     to_date('8/9/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual)
select person_id, var_match, overlap_num, relation_id, start_dt, end_dt, start_dt_overlap, end_dt_overlap
  from t
  match_recognize (
  partition by person_id order by start_dt
  measures 
    classifier() as var_match,
    match_number() as overlap_num,
    last(start_dt) as start_dt_overlap,
    first(end_dt) as end_dt_overlap
  all rows per match
  after match skip to last ovlap
  pattern (strt ovlap+)
  define ovlap as (strt.relation_id = -1 and start_dt <= strt.end_dt)
                  or (ovlap.relation_id = -1 and strt.start_dt <= prev(strt.end_dt))
  )
  order by person_id, overlap_num, start_dt;

示例执行:

FSITJA@db01 2019-07-11 14:55:17> with t (PERSON_ID,RELATION_ID,RELATION_NAME,START_DT,  END_DT, ACTIVE_IND,LATEST_ROW) as (
  2  select 'STEVE',     -1,          'NONE',        to_date('7/26/2018', 'MM/DD/YYYY'), to_date('10/24/2018', 'MM/DD/YYYY'), 'Y', 'N' from dual union all
  3  select 'STEVE',     111,         'STUDENT',      to_date('8/8/2018', 'MM/DD/YYYY'), to_date('10/22/2018', 'MM/DD/YYYY'), 'Y', 'N' from dual union all
  4  select 'STEVE',     111,         'STUDENT',      to_date('10/23/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
  5  select 'STEVE',     -1,          'NONE',         to_date('10/25/2018', 'MM/DD/YYYY'), to_date('2/7/2019', 'MM/DD/YYYY'),   'Y', 'N' from dual union all
  6  select 'STEVE',     222,         'Manager',      to_date('8/9/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
  7  select 'BOB',       333,         'ASSOCIATE',    to_date('8/9/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
  8  select 'BOB',       666,         'TEACHER',      to_date('8/10/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual union all
  9  select 'Dave',      555,         'Director',     to_date('8/9/2018', 'MM/DD/YYYY'), to_date('12/31/4712', 'MM/DD/YYYY'), 'Y', 'Y' from dual)
 10  select person_id, var_match, overlap_num, relation_id, start_dt, end_dt, start_dt_overlap, end_dt_overlap
 11    from t
 12    match_recognize (
 13    partition by person_id order by start_dt
 14    measures
 15      classifier() as var_match,
 16      match_number() as overlap_num,
 17      last(start_dt) as start_dt_overlap,
 18      first(end_dt) as end_dt_overlap
 19    all rows per match
 20    after match skip to last ovlap
 21    pattern (strt ovlap+)
 22    define ovlap as (strt.relation_id = -1 and start_dt <= strt.end_dt)
 23                    or (ovlap.relation_id = -1 and strt.start_dt <= prev(strt.end_dt))
 24    )
 25    order by person_id, overlap_num, start_dt;

PERSO VAR_MATCH  OVERLAP_NUM RELATION_ID START_DT            END_DT              START_DT_OVERLAP    END_DT_OVERLAP
----- ---------- ----------- ----------- ------------------- ------------------- ------------------- -------------------
STEVE STRT                 1          -1 2018-07-26 00:00:00 2018-10-24 00:00:00 2018-07-26 00:00:00 2018-10-24 00:00:00
STEVE OVLAP                1         111 2018-08-08 00:00:00 2018-10-22 00:00:00 2018-08-08 00:00:00 2018-10-24 00:00:00
STEVE OVLAP                1         222 2018-08-09 00:00:00 4712-12-31 00:00:00 2018-08-09 00:00:00 2018-10-24 00:00:00
STEVE OVLAP                1         111 2018-10-23 00:00:00 4712-12-31 00:00:00 2018-10-23 00:00:00 2018-10-24 00:00:00
STEVE STRT                 2         111 2018-10-23 00:00:00 4712-12-31 00:00:00 2018-10-23 00:00:00 4712-12-31 00:00:00
STEVE OVLAP                2          -1 2018-10-25 00:00:00 2019-02-07 00:00:00 2018-10-25 00:00:00 4712-12-31 00:00:00

6 rows selected.