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
我的示例数据库(实际上是 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