SQL - 根据日期差异选择行

时间:2021-02-23 07:10:51

标签: sql oracle

假设我们有下表:

<头>
代码 Dt
c1 2020-10-01
c1 2020-10-05
c1 2020-10-09
c1 2020-10-10
c1 2020-10-20
c2 2020-10-07
c2 2020-10-09
c2 2020-10-15
c2 2020-10-16
c2 2020-10-20
c2 2020-10-24

Code 和 Dt 的组合是独一无二的。行根据 Code 和 Dt 进行排序。数据库是 Oracle 12。 对于每个代码,我想获取其 Dt 列表,与之前选择的 Dt 相比,每个 Dt 大于 7 天。因此,结果应该是:

<头>
代码 Dt
c1 2020-10-01
c1 2020-10-09
c1 2020-10-20
c2 2020-10-07
c2 2020-10-15
c2 2020-10-24

如果日期差异大于 7,我已经尝试过基于 row_number() 的自连接将每一行与其前一行连接起来。在表中。任何解决方案?谢谢

2 个答案:

答案 0 :(得分:5)

您可以使用 match_recognize

相对轻松地解决这个问题
with data(code, dt) as (
  select 'c1',  to_date('2020-10-01', 'YYYY-MM-DD') from dual union all
  select 'c1',  to_date('2020-10-05', 'YYYY-MM-DD') from dual union all
  select 'c1',  to_date('2020-10-09', 'YYYY-MM-DD') from dual union all
  select 'c1',  to_date('2020-10-10', 'YYYY-MM-DD') from dual union all
  select 'c1',  to_date('2020-10-20', 'YYYY-MM-DD') from dual union all
  select 'c2',  to_date('2020-10-07', 'YYYY-MM-DD') from dual union all
  select 'c2',  to_date('2020-10-09', 'YYYY-MM-DD') from dual union all
  select 'c2',  to_date('2020-10-15', 'YYYY-MM-DD') from dual union all
  select 'c2',  to_date('2020-10-16', 'YYYY-MM-DD') from dual union all
  select 'c2',  to_date('2020-10-20', 'YYYY-MM-DD') from dual union all
  select 'c2',  to_date('2020-10-24', 'YYYY-MM-DD') from dual
)
select *
from data match_recognize (
  partition by code
  order by dt
  measures
   init.dt dt
  one row per match
  pattern (init less_than_7_days*)
  define
    less_than_7_days as less_than_7_days.dt - init.dt < 7
)

您只需按代码分区,按日期排序,然后获取日期差异小于 7(与 init 相比)的任何行 init 和 0-many 以下行 (less_than_7_days*)。您为整个匹配返回 1 行(初始化 + 后续行),其中包含来自 init

的日期

答案 1 :(得分:1)

看起来像一个层次查询的案例。 计算对并遍历链

with pairs(Code, Dt, dtnext) as (
  select t1.Code, t1.dt, Min(t2.dt)
  from tbl t1
  join tbl t2 on t1.code=t2.code and t2.dt >= t1.dt + INTERVAL '7' DAY
  group by t1.Code, t1.dt
),
h(Code, Dtn) as (
  select Code,  Min(dt)
  from tbl
  group by Code
  union all
  select h.Code, p.dtnext
  from h
  join pairs p on p.code=h.code and p.Dt= h.dtn
  )
select * 
from h
order by code, dtn

The fiddle

退货

CODE    DTN
c1  01-OCT-20
c1  09-OCT-20
c1  20-OCT-20
c2  07-OCT-20
c2  15-OCT-20
c2  24-OCT-20