不同组的 Oracle SQL 领先滞后

Posted

技术标签:

【中文标题】不同组的 Oracle SQL 领先滞后【英文标题】:Oracle SQL lead lag across different group 【发布时间】:2020-05-31 19:59:12 【问题描述】:

假设我有下表。他们的关键就是 concat 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   3   abx
a   b   c   3   abc

预期结果集:

KEY OPERATION DAY

abc  ADD      1
abe  ADD      2
aby  ADD      2
abc  REMOVE   2
abx  ADD      3
abc  ADD      3
abe  REMOVE   3
aby  REMOVE   3

如果一天不是连续的怎么办。例如:

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

而预期的结果是:

KEY OPERATION DAY

abc  ADD      1
abe  ADD      2
aby  ADD      2
abc  REMOVE   2
abx  ADD      5
abc  ADD      5
abe  REMOVE   5
aby  REMOVE   5

【问题讨论】:

【参考方案1】:

这是一种使用lag()lead() 的方法。这个想法是比较每个键的前一个和后一个日期值,并使用它来识别添加或删除键的日期 - 这假设 day 是一个按顺序递增的数字,没有间隙。

with cte as (
    select
        t.*,
        lag(day) over(partition by p1, p2, p3 order by day) lag_day,
        lead(day) over(partition by p1, p2, p3 order by day) lead_day
    from mytable t
)
select p1, p2, p3, day, 'add' event
from cte
where lag_day is null or lag_day <> day - 1 
union all
select p1, p2, p3, day + 1, 'remove'
from cte
where lead_day is null or lead_day <> day + 1 
order by day, p1, p2, p3

使用 this db fiddle 中的示例数据,这会产生:

P1 | P2 | P3 |天 |事件 :- | :- | :- | --: | :----- 一个 |乙 | c | 1 |添加 一个 |乙 | c | 2 |消除 一个 |乙 |电子| 2 |添加 一个 |乙 |是 | 2 |添加 一个 |乙 | c | 3 |添加 一个 |乙 |电子| 3 |消除 一个 |乙 | x | 3 |添加 一个 |乙 |是 | 3 |消除 一个 |乙 | c | 4 |消除 一个 |乙 | x | 4 |消除

这似乎比您预期的结果更完整。请注意,在最后一天仍然可用的所有记录在下一天(假设的)显示为已删除 - 这似乎与所有新记录在第一天显示为添加的事实一致。

我没有使用伪键,因为它看不出它有什么帮助 - 而且,如果值有多个字符,它可能会通过创建“错误”重复项而导致麻烦。

【讨论】:

我觉得这很棒。实际上,它与天之间有差距。我在想需要先排名天数,然后在排名中领先一圈吗?例如,第 2 天可以有多个带有不同键的时间戳【参考方案2】:

如果需要,您可以在没有窗口函数的情况下执行此操作:

select key, 'add', day
from t
where not exists (select 1
                  from t t2
                  where t2.key = t.key and t2.day = t.day - 1
                 )
union all
select key, 'remove', day + 1
from t
where not exists (select 1
                  from t t2
                  where t2.key = t.key and t2.day = t.day + 1
                 )

【讨论】:

以上是关于不同组的 Oracle SQL 领先滞后的主要内容,如果未能解决你的问题,请参考以下文章

Oracle滞后函数

明智地显示员工表部门的运行工资,而不使用滞后、领先或分区

如何在 MongoDB 中执行领先和滞后

关于数据库 Oracle 和 SQL Serve

如何使用SYS用户连接ORACLE数据库?

在oracle数据库中,要求两个字段的和要怎么写sql语句