T-SQL 比较前一个非NULL和当前行按差值过滤掉

T-SQL Compare previous non-NULL and current row to filter out by difference value

我的示例数据库(实际上是 CTE 语句数据)如下所示:

eventdate   val
2012-03-23  3965
2012-03-26  3979
2012-03-27  3974
2012-03-28  3965
2012-03-29  3967
2012-03-30  3959
2012-04-02  3951
2012-04-03  3961
2012-04-04  3944
2012-04-05  3935
2012-04-09  3901
2012-04-10  3822

我想删除相差小于 12 的值。 这是我的查询和输出:

SELECT
eventdate,
CASE
WHEN ABS(val - LAG(val) OVER (ORDER BY eventdate)) <= 12
THEN NULL
ELSE val
END AS val
FROM tbl_1
ORDER BY eventdate

问题是它在当前行和上一行之间进行比较。 这是我得到的:

eventdate   val
2012-03-23  3965
2012-03-26  3979
2012-03-27  NULL
2012-03-28  NULL
2012-03-29  NULL
2012-03-30  NULL
2012-04-02  NULL
2012-04-03  NULL
2012-04-04  3944
2012-04-05  NULL
2012-04-09  3901
2012-04-10  3822

我需要比较当前和之前的非 NULL 值,我指的是在上一步中未为 NULL 的最后一个值。

这是我需要的:

eventdate   val
2012-03-23  3965
2012-03-26  3979
2012-03-27  NULL
2012-03-28  3965
2012-03-29  NULL
2012-03-30  NULL
2012-04-02  3951
2012-04-03  NULL
2012-04-04  NULL
2012-04-05  3935
2012-04-09  3901
2012-04-10  3822

我尝试了以下方法。我做了一个自引用的 CTE 查询,如上所述用 THEN LAG(val) OVER (ORDER BY eventdate) 替换 THEN NULL 以复制最后一个适当的值并与下一个进行比较。然后删除重复项。但它在 OPTION (MAXRECURSION 0) 上致命循环,根本没有输出。

似乎这只能由 CURSOR 完成。我需要将结果集作为 CTE 语句(CTE 中的 CURSOR 操作),以便在下一个查询中使用它。

就我寻找的 CURSOR 个示例而言,它们都是作为 CTE 的最终 SELECT 完成的。这不是我的选择!

我是运行SQLServer 2014.

非常感谢您的帮助或想法!

这样就可以了:

declare @tbl_1 table (eventdate date, val int)
insert into @tbl_1(eventdate,val) values
('20120323',3965),
('20120326',3979),
('20120327',3974),
('20120328',3965),
('20120329',3967),
('20120330',3959),
('20120402',3951),
('20120403',3961),
('20120404',3944),
('20120405',3935),
('20120409',3901),
('20120410',3822)

;With Ord as (
    select eventdate,val,ROW_NUMBER() OVER (ORDER BY eventdate) as rn
    from @tbl_1
), Runs as (
    select eventdate,val,val as prevval,rn
    from Ord
    where rn = 1
    union all
    select
        o.eventdate,
        CASE WHEN ABS(o.val - r.prevval) <= 12 THEN NULL ELSE o.val END,
        CASE WHEN ABS(o.val - r.prevval) <= 12 THEN r.prevval ELSE o.val END,
        o.rn
    from
        Runs r
            inner join
        Ord o
            on
                r.rn = o.rn - 1
)
SELECT
    r.eventdate,r.val
from Runs r

希望您能看到我们对两个新 CTE 所做的工作 - 第一个 (Ord) 只是很好地设置,以便我们可以轻松地在 Runs 中执行自连接在 "current" 行和前一行之间 - 您可以将其逻辑合并到当前的 CTE 中,从而为我们提供此结果集。

Runs 中,我们还添加了一个新列 (prevval),其中 "remembers" 使用了最后一个非 NULL 值。它会生成您要求的结果集:

eventdate  val
---------- -----------
2012-03-23 3965
2012-03-26 3979
2012-03-27 NULL
2012-03-28 3965
2012-03-29 NULL
2012-03-30 NULL
2012-04-02 3951
2012-04-03 NULL
2012-04-04 NULL
2012-04-05 3935
2012-04-09 3901
2012-04-10 3822

如果仍然不清楚它做了什么,请将最后的 select 替换为 SELECT *:

eventdate  val         prevval     rn
---------- ----------- ----------- --------------------
2012-03-23 3965        3965        1
2012-03-26 3979        3979        2
2012-03-27 NULL        3979        3
2012-03-28 3965        3965        4
2012-03-29 NULL        3965        5
2012-03-30 NULL        3965        6
2012-04-02 3951        3951        7
2012-04-03 NULL        3951        8
2012-04-04 NULL        3951        9
2012-04-05 3935        3935        10
2012-04-09 3901        3901        11
2012-04-10 3822        3822        12