访问SQL中的上一行

时间:2019-06-27 12:23:22

标签: sql oracle

我有以下数据:

ID Begin_Dt End_DT 
101 201205   201208
101 201301   201309
101 201401   201502
101 201701   201801

现在,如果begin_DT是距上一个实例结束日期<= 9个月,则我需要覆盖end_dt或具有下一行的end_dt的上一行。我需要重复一遍,直到差异<= 9

让我们计算差异>>

Row_num ID Begin_Dt End_DT    Diff
1   101 201205   201208    NA
2   101 201301   201309    5
3   101 201401   201502    4
4   101 201701   201801    23

第2行和第3行的差异为<= 9,因此解决方案应为

ID Begin_Dt End_DT   Flag_corr
101 201205   201502   1
101 201301   201502   1
101 201401   201502   0
101 201701   201801   0

3 个答案:

答案 0 :(得分:0)

尝试使用LAG功能。

with q0 as (
    -- convert numbers to date and calculate lag
    select to_date(begin_dt,'yyyymm') as begin_dt,
    to_date(end_dt,'yyyymm') as end_dt,
    lag(to_date(end_dt,'yyyymm'),1) over(order by begin_dt) as end_dt_prev
    from dt
)


-- calculate difs and create flag
select q0.*,
months_between(end_dt,end_dt_prev) as diff,
case when months_between(end_dt,end_dt_prev) > 9 then 1 else 0 end as flag
from q0

答案 1 :(得分:0)

这是一种形式的空缺和岛屿问题,岛屿由9个月的空缺定义。开始的累积总和(基于滞后)定义了组;然后再执行一个步骤即可获得最大日期:

"Exception: Module loading registration_form failed: file 
 registration_form/security/ir.model.access.csv could not be processed:
 No matching record found for external id 'model_registration_management' 
 in field 'Object' No matching record found for external id 
 'registration.group_management_user' in field 'Group'
 Missing required value for the field 'Object' (model_id) - - -
 Missing required value for the field 'Object' ("

答案 2 :(得分:0)

您说“我需要重复一遍,直到差异<= 9”。对我来说,这意味着您希望将行分组在一起,只要它们之间的总间隔不超过9个月即可。我不确定其他答案会尝试这样做。

您应该始终说出您所使用的Oracle数据库的版本。如果您使用的是12c或更高版本,则可以使用出色的MATCH_RECOGNIZE子句:

with data(ID,Begin_Dt,End_DT ) as (
  select 101, to_date('201205', 'yyyymm'), to_date('201208', 'yyyymm') from dual union all
  select 101, to_date('201301', 'yyyymm'), to_date('201309', 'yyyymm') from dual union all
  select 101, to_date('201401', 'yyyymm'), to_date('201502', 'yyyymm') from dual union all
  select 101, to_date('201701', 'yyyymm'), to_date('201801', 'yyyymm') from dual
)
select * from (
  select d.*,
    months_between(
      begin_dt,
      lag(end_dt,1,begin_dt) over(partition by id order by end_dt)
    ) mon
  from data d
)
match_recognize(
  partition by id order by begin_dt
  measures final last(end_dt) new_end_dt
  all rows per match
  pattern(a b*)
  define b as sum(mon) <= 9
);

ID  BEGIN_DT          NEW_END_DT         END_DT             MON 
101 2012-05-01 00:00  2015-02-01 00:00   2012-08-01 00:00     0 
101 2013-01-01 00:00  2015-02-01 00:00   2013-09-01 00:00     5 
101 2014-01-01 00:00  2015-02-01 00:00   2015-02-01 00:00     4 
101 2017-01-01 00:00  2018-01-01 00:00   2018-01-01 00:00    23