需要获取具有特定值的后续记录

时间:2019-05-23 04:38:34

标签: sql tsql sql-server-2012

我有下表:

        Dt          Status
05.23.2019 10:00:00   A
05.23.2019 11:00:00   B
05.23.2019 12:00:00   B
05.23.2019 13:00:00   D
05.23.2019 14:00:00   A
05.23.2019 15:00:00   B
05.23.2019 16:00:00   C
05.23.2019 17:00:00   D
05.23.2019 18:00:00   A

对于每个状态A,我需要获取下一个状态D。结果应如下所示:

Status1   Status2  Dt1                  Dt2
A         D        05.23.2019 10:00:00  05.23.2019 13:00:00
A         D        05.23.2019 14:00:00  05.23.2019 17:00:00
A         null     05.23.2019 18:00:00  null

我有基于交叉/外部申请的我自己的解决方案,就性能而言,我需要没有交叉/外部申请的解决方案。

2 个答案:

答案 0 :(得分:1)

我们可以在此处尝试使用ROW_NUMBER以及一些枢轴逻辑:

WITH cte AS (
    SELECT *,
        ROW_NUMBER() OVER (PARTITION BY Status ORDER BY Dt) rn
    FROM yourTable
    WHERE Status IN ('A', 'D')
)

SELECT
    MAX(CASE WHEN Status = 'A' THEN Status END) AS Status1,
    MAX(CASE WHEN Status = 'D' THEN Status END) AS Status2,
    MAX(CASE WHEN Status = 'A' THEN Dt END) AS Dt1,
    MAX(CASE WHEN Status = 'D' THEN Dt END) AS Dt2
FROM cte
GROUP BY rn
ORDER BY rn;

enter image description here

Demo

这里的想法是为每个单独的Status值(A或D)在整个表格中生成一个行号序列。然后,按照该行号顺序进行汇总,以将A和D记录放在一起。

答案 1 :(得分:1)

由于结果列Status1Status2分别始终总是分别为“ A”和“ D”,因此我在结果中省略了它们。

DECLARE @Data TABLE
(
    [Dt] SMALLDATETIME,
    [Status] CHAR(1)
);

INSERT INTO @Data ([Dt], [Status]) VALUES
    ('2019-05-23 10:00:00', 'A'),
    ('2019-05-23 11:00:00', 'B'),
    ('2019-05-23 12:00:00', 'B'),
    ('2019-05-23 13:00:00', 'D'),
    ('2019-05-23 14:00:00', 'A'),
    ('2019-05-23 15:00:00', 'B'),
    ('2019-05-23 16:00:00', 'C'),
    ('2019-05-23 17:00:00', 'D'),
    ('2019-05-23 18:00:00', 'A'),
    ('2019-05-23 19:00:00', 'D'),
    ('2019-05-23 20:00:00', 'D'),
    ('2019-05-23 21:00:00', 'A'),
    ('2019-05-23 22:00:00', 'A'),
    ('2019-05-23 23:00:00', 'A');

SELECT
    D.[Dt] AS [Dt1],
    [LastDBeforeNextA].[Dt] AS [Dt2]
FROM
    @Data AS D
    OUTER APPLY (SELECT TOP (1) [Dt]
                 FROM @Data
                 WHERE [Status] = 'A' AND [Dt] > D.[Dt]
                 ORDER BY [Dt]) AS [NextA]
    OUTER APPLY (SELECT TOP (1) [Dt]
                 FROM @Data
                 WHERE [Status] = 'D' AND [Dt] < [NextA].[Dt] AND [Dt] > D.[Dt]
                 ORDER BY [Dt] DESC) AS [LastDBeforeNextA]
WHERE
    D.[Status] = 'A' AND
    ([NextA].[Dt] > [LastDBeforeNextA].[Dt] OR ([LastDBeforeNextA].[Dt] IS NULL AND [NextA].[Dt] IS NULL))

它最初从状态为'A'的表中获取所有记录(使用WHERE子句中的表达式D.[Status] = 'A')。

对于找到的每个记录,它将状态为A的下一条记录的日期(别名为NextA的表表达式)与状态D的最后一条记录的日期紧接在下一条A记录之前,但是在当前A记录之后(别名为LastDBeforeNextA的表表达式)。

当找到D记录(在WHERE子句中的表达式[NextA].[Dt] > [LastDBeforeNextA].[Dt])或尚无D记录(在WHERE子句中的表达式[LastDBeforeNextA].[Dt] IS NULL)时,结果有效。在后一种情况下,您需要获取最新的A记录(WHERE子句中的表达式[NextA].[Dt] IS NULL),因为在最后一个D记录之后可以有多个A记录。