oracle sql领先滞后于整个组的历史数据

nzrxty8p  于 2021-08-13  发布在  Java
关注(0)|答案(1)|浏览(422)

我问了一个类似的问题。假设我有下表结构。p1,p2,p3这3个属性表示为一个键。我想每天比较每把钥匙。例如,从第1天到第2天,删除,添加abe和aby。

P1  P2  P3  DAY  KEY

a   b   c   1    abc
a   b   e   2    abe
a   b   y   2    aby
a   b   x   5    abx
a   b   c   5    abc

我正在考虑生成一个结果集,该结果集具有跟踪历史的开始/结束日期。预期结果集:

P1  P2  P3      KEY  STARTTIME  ENDTIME

a   b   c       abc     1         2
a   b   e       abe     2         5
a   b   y       aby     2         5
a   b   x       abx     5        NULL
a   b   c       abc     5        NULL

谢谢你为我之前的帖子提供帮助。我修改了下面的一个答案,以获得添加/删除结果集,但仍然无法转换为上面的开始/结束时间模型。

with base as (
select
    'a' as p1,
    'b' as p2,
    'c' as p3,
    1 as day
from dual
union
select
    'a' as p1,
    'b' as p2,
    'y' as p3,
    2 as day
from dual
union
select
    'a' as p1,
    'b' as p2,
    'e' as p3,
    2 as day
from dual
union
select
    'a' as p1,
    'b' as p2,
    'x' as p3,
    5 as day
from dual
union
select
    'a' as p1,
    'b' as p2,
    'c' as p3,
    5 as day
from dual
),
calendar as (
select
    day,
    lead(day) over (order by day asc) as nextday,
    lag(day) over (order by day asc) as prevday
from
    (select distinct day from base)
),
data as (
    select
        p1,
        p2,
        p3,
        base.day,
        lead(base.day) over (partition by p1, p2, p3 order by base.day asc) as nextrow,
        lag(base.day) over (partition by p1, p2, p3 order by base.day asc) as prevrow,
        calendar.nextday,
        calendar.prevday
    from 
        base
    left join
        calendar
            on calendar.day = base.day
)
select * from data
/

select
    d1.p1,
    d1.p2,
    d1.p3,
    d1.day,
    d1.nextrow,
    d1.prevrow,
    'ADD' as op,
    d1.day as d
from 
    data d1
where
    prevrow is null or prevrow <> prevday
union
select
    d2.p1,
    d2.p2,
    d2.p3,
    d2.day,
    d2.nextrow,
    d2.prevrow,
    'REMOVE' as op,
    nextday
from 
    data d2
where
    nextrow is null or nextrow <> nextday
order by
    d, op asc
nwsw7zdq

nwsw7zdq1#

我认为这是一个缺口和孤岛问题。您可以使用行号之间的差异来标识相邻记录的组。计算 end_day ,需要更多的逻辑,因为日子不是连续的:我用了一个窗口 sum() 随着时间的推移 first_value() 要获得实际的“下一个”日期:

select 
    p1, 
    p2,
    p3,
    min(day) over(partition by p1, p2, p3, rn1 - rn2 order by day) start_day,
    case 
        when min(day) over(partition by p1, p2, p3, rn1 - rn2 order by day) 
            <> max(lead_day) over()
        then max(lead_day) over(partition by day_grp) 
    end end_day
from (
    select 
        t.*,
        sum(case when day = lead_day then 0 else 1 end) over(order by day) day_grp
    from (
    select
        t.*,
        row_number() over(order by day) rn1,
        row_number() over(partition by p1, p2, p3 order by day) rn2,
        lead(day) over(order by day) lead_day
    from mytable t
    ) t
) t

db fiddlde上的演示:

P1 | P2 | P3 | START_DAY | END_DAY
:- | :- | :- | --------: | ------:
a  | b  | c  |         1 |       2
a  | b  | e  |         2 |       5
a  | b  | y  |         2 |       5
a  | b  | x  |         5 |    null
a  | b  | c  |         5 |    null

相关问题