【问题标题】:Select each distinct value over time without losing NULLs in between随着时间的推移选择每个不同的值,而不会丢失两者之间的 NULL
【发布时间】:2021-12-24 20:45:52
【问题描述】:

让我们假设一个表有很多列并且一个 Temporal 表正在记录它的历史。当它发生变化时,我需要知道一个字段。

Number VersionStartDate
991281 2021-11-12 08:27:11
991281 2021-11-12 08:20:11
NULL 2021-11-12 07:20:11
NULL 2021-11-12 06:20:11
771281 2021-11-11 08:26:11
NULL 2021-11-11 08:25:11
661281 2021-11-10 08:24:11
NULL 2021-11-10 08:22:11
661281 2021-11-10 08:21:11
551281 2021-11-09 08:20:11

我需要获取每个值,以及它改变的那一刻。我还需要知道它是否被设置为 NULL,所以这个查询没有给出我需要的。

SELECT
    Number,
    MIN(VersionStartDate) [Date]
FROM _TABLE_ 
GROUP BY
    Number
ORDER BY
    [Date] DESC

结果应该是

Number VersionStartDate
991281 2021-11-12 08:20:11
NULL 2021-11-12 06:20:11
771281 2021-11-11 08:26:11
NULL 2021-11-11 06:25:11
661281 2021-11-10 08:24:11
NULL 2021-11-10 08:22:11
661281 2021-11-10 08:21:11
551281 2021-11-09 08:20:11

【问题讨论】:

  • 您在这里看到的似乎是一个孤岛问题。 MIN 本身是行不通的。
  • 每个非空数字只需要一次吗?
  • @Larnu 谢谢,知道它的调用将如何帮助我找到解决方案
  • @jarlh 如果还有另一个值 551281、NULL、551281,那么我想要两个,如果它在 (551281,551281) 之后,那么我想要它不同
  • 添加反映这一点的样本数据,并相应地调整预期结果。

标签: sql sql-server tsql gaps-and-islands


【解决方案1】:

在您的组中添加 VersionStartDate。

SELECT
    Number,
    MIN(VersionStartDate)
FROM _TABLE_ 
GROUP BY
    Number, VersionStartDate
ORDER BY
    VersionStartDate DESC

【讨论】:

  • 按版本开始日期分组将返回每一行
【解决方案2】:

嗯,这是一种方法,我相信还有一种更雄辩的方法来编写它,但它会让你开始:

CREATE TABLE #T(Number int, VersionStartDate datetime)
INSERT INTO #T vALUES
(991281,'2021-11-12 08:27:11'),
(991281,'2021-11-12 08:20:11'),
(NULL,'2021-11-12 07:20:11'),
(NULL,'2021-11-12 06:20:11'),
(771281,'2021-11-11 08:26:11'),
(NULL,'2021-11-11 08:25:11'),
(661281,'2021-11-10 08:24:11'),
(NULL,'2021-11-10 08:22:11'),
(661281,'2021-11-10 08:21:11'),
(551281,'2021-11-09 08:20:11')


SELECT Number, MIN(VersionStartDate) VersionStartDate
FROM
(
    SELECT *, SUM(CASE WHEN ISNULL(Number,-1) <> ISNULL(LG,-1) THEN 1 ELSE 0 END) OVER(ORDER BY VersionStartDate desc) GRP
    FROM
    (
        SELECT *, LAG(Number,1,-1) OVER(ORDER BY VersionStartDate desc) LG
        FROM #T
    ) X
) Y
GROUP BY GRP,Number
ORDER BY VersionStartDate desc

【讨论】:

    【解决方案3】:

    与我开始研究后出现的 JMabee 非常相似,但可能更简单一些:

    CREATE TABLE #d (Number INT, VersionStartDate DATETIME);
    INSERT INTO #d(Number, VersionStartDate) 
    VALUES
    (991281 ,'2021-11-12T08:27:11'),
    (991281 ,'2021-11-12T08:20:11'),
    (NULL   ,'2021-11-12T07:20:11'),
    (NULL   ,'2021-11-12T06:20:11'),
    (771281 ,'2021-11-11T08:26:11'),
    (NULL   ,'2021-11-11T08:25:11'),
    (661281 ,'2021-11-10T08:24:11'),
    (NULL   ,'2021-11-10T08:22:11'),
    (661281 ,'2021-11-10T08:21:11'),
    (551281 ,'2021-11-09T08:20:11');
    
    WITH cte AS
    (
        SELECT  Number,
                VersionStartDate,
                LAG(Number, 1) OVER (ORDER BY VersionStartDate) AS PrevNumber
        FROM    #d
    )
    SELECT      cte.Number,
                cte.VersionStartDate
    FROM        cte
    WHERE       ISNULL(cte.Number, -1) <> ISNULL(cte.PrevNumber, -1)
    ORDER BY    cte.VersionStartDate DESC;
    

    【讨论】:

    • 我更喜欢您的解决方案,因为使用 CTE 而不是子查询
    猜你喜欢
    • 1970-01-01
    • 2019-11-17
    • 2011-08-17
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    • 2018-06-25
    相关资源
    最近更新 更多