【问题标题】:SQL Server Lag / Lead Across Groups / Dense RankSQL Server 滞后/跨组领先/密集排名
【发布时间】:2019-01-30 12:49:41
【问题描述】:

我希望找到有关如何填写超前值和滞后值的答案。

输入:

BRAND   Promo_Start VALUE
TESLA   2016-06-05  NULL
TESLA   2016-06-12  NULL
TESLA   2016-06-19  40000
TESLA   2016-06-26  75000
TESLA   2016-07-03  75000
TESLA   2016-07-10  NULL

我想要的输出是:

BRAND   Promo_Start VALUE
TESLA   2016-06-05  40000
TESLA   2016-06-12  40000
TESLA   2016-06-19  40000
TESLA   2016-06-26  75000
TESLA   2016-07-03  75000
TESLA   2016-07-10  75000

我已经能够填写最后一个值,但是,我没有成功填写前两个值。

BRAND   Promo_Start VALUE   FILLED_VALUE
TESLA   2016-06-05  NULL    NULL
TESLA   2016-06-12  NULL    NULL
TESLA   2016-06-19  40000   40000
TESLA   2016-06-26  75000   75000
TESLA   2016-07-03  75000   75000
TESLA   2016-07-10  NULL    75000

使用这个查询:

WITH help1 as (
SELECT *,
CASE WHEN [VALUE] IS NULL THEN 0 ELSE 1 END CHANGEINDICATOR
FROM #SOExample
)
, help2 as (
SELECT *, SUM(CHANGEINDICATOR) OVER (ORDER BY [Promo_Start]) RowGroup from help1
)
SELECT [BRAND],[Promo_Start],[VALUE],
CASE WHEN [VALUE] IS NOT NULL THEN [VALUE]
ELSE FIRST_VALUE([VALUE]) OVER (PARTITION BY RowGroup ORDER BY [Promo_Start])
END [FILLED_VALUE]
FROM help2
GO

表是使用以下方法创建的:

CREATE TABLE #SOExample
    ([BRAND] varchar(10),[Promo_Start] varchar(10), [VALUE] varchar(15))
;
GO

INSERT INTO #SOExample
    ([BRAND],[Promo_Start], [VALUE])
VALUES
    ('TESLA', '2016-06-05',NULL),
    ('TESLA', '2016-06-12',NULL),
    ('TESLA', '2016-06-19','40000'),
    ('TESLA', '2016-06-26','75000'),
    ('TESLA', '2016-07-03','75000'),
    ('TESLA', '2016-07-10',NULL)
;
GO

我认为这个问题可能类似于:LAG() / LEAD() of the next rank (Postgresql) 我查看了 this 创建标志和 this 因为这似乎是一个类似的问题。

我还研究了 dense_rank 并使用了更改指示器(从 NULL 更改为下一行中的值,并将值更改为下一行中的 NULL)。

【问题讨论】:

  • 需要的逻辑是什么?获取下一个或上一个非空 VALUE ?如果2016-06-26 有一个NULL 值,应该是什么值?
  • @Squirrel 嗨!是的,逻辑显示在输入表下方列出的输出表中。如果原始值不为 NULL,则输出值应与原始值相同。所以因为 2016-06-26 有一个非空值,那么它的输出值应该和它原来的一样,75000。

标签: sql-server tsql window-functions sql-server-2017 lead


【解决方案1】:

你只需要处理RowGroup = 0时的情况

WITH help1 as (
SELECT *,
CASE WHEN [VALUE] IS NULL THEN 0 ELSE 1 END CHANGEINDICATOR
FROM #SOExample
)
, help2 as (
SELECT *, SUM(CHANGEINDICATOR) OVER (ORDER BY [Promo_Start]) RowGroup from help1
)
SELECT [BRAND],[Promo_Start],[VALUE],
CASE WHEN RowGroup = 0 THEN (Select [value] from help2 where RowGroup = 1)
ELSE FIRST_VALUE([VALUE]) OVER (PARTITION BY RowGroup ORDER BY [Promo_Start])
END [FILLED_VALUE]
FROM help2

【讨论】:

    【解决方案2】:

    2 OUTER APPLY,第一个获取下一个非空值,第二个获取上一个非空值。

    SELECT  *, NEW_VALUE = COALESCE ( so.VALUE, n.FILLED_VALUE, p.FILLED_VALUE)
    FROM    #SOExample so
            OUTER APPLY
            (
                SELECT  TOP 1 FILLED_VALUE = x.VALUE
                FROM    #SOExample x
                WHERE   x.BRAND     = so.BRAND
                AND     x.Promo_Start   >= so.Promo_Start
                AND     x.VALUE     IS NOT NULL
                ORDER BY x.Promo_Start
            ) n
            OUTER APPLY
            (
                SELECT  TOP 1 FILLED_VALUE = x.VALUE
                FROM    #SOExample x
                WHERE   x.BRAND         = so.BRAND
                AND     x.Promo_Start   <= so.Promo_Start
                AND     x.VALUE     IS NOT NULL
                ORDER BY x.Promo_Start DESC
            ) p
    

    【讨论】:

    • 这很好用!谢谢!!如何删除 FILLED_VALUE 列?我可以使用 CASE WHEN 语句吗?
    • 不要使用SELECT *。明确指定列名
    • 如果我要填写多个值,如何重新应用?我有 [BRAND],[Promo_Start],[VALUE],[Resale Value],[Otra Value] 我想要 [BRAND],[Promo_Start],[VALUE],[FILLED_VALUE],[Resale Value],[Filled Resale值]、[Otra 值]、[填充 Otra 值]。 VALUE、Resale Value 和 Otra Value 的第一个非空值通常不在同一行中。
    • 您将需要多个 OUTER APPLY 部分。每个为一列
    • 这就是我最终要做的!谢谢!
    猜你喜欢
    • 1970-01-01
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2023-04-04
    • 1970-01-01
    相关资源
    最近更新 更多