【问题标题】:Oracle SQL Lead Lag across group for historical dataOracle SQL Lead Lag 跨组的历史数据
【发布时间】:2020-06-01 02:38:32
【问题描述】:

我问了一个类似的问题here。假设我有下表结构。 P1、P2、P3 这三个属性表示为一个键。我想每天比较每个键。例如,从第 1 天到第 2 天,删除 abc 并添加 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

【问题讨论】:

  • KEY 列的意义何在?如果只是(P1, P2, P3)的串联,那就别管它了;你不需要它(即使你认为你需要),它最终会给你带来麻烦。
  • 此外,DAY=3 没有出现任何“键”组合;这是否意味着它们都在 DAY=2(或更早)结束?如果不是,为什么不呢?我在您的帖子中没有看到对此的解释。

标签: sql oracle window-functions gaps-and-islands


【解决方案1】:

我将其理解为差距和孤岛问题。您可以使用行号之间的差异来识别相邻记录的组。要计算 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

Demo on DB Fiddlde

P1 | P2 | P3 | START_DAY | END_DAY :- | :- | :- | --------: | ------: 一个 |乙 | c | 1 | 2 一个 |乙 |电子| 2 | 5 一个 |乙 |是 | 2 | 5 一个 |乙 | x | 5 | 一个 |乙 | c | 5 |

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    • 1970-01-01
    • 2016-01-21
    • 2016-09-19
    • 1970-01-01
    • 2018-04-14
    相关资源
    最近更新 更多