我有下表:
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
我有基于交叉/外部申请的我自己的解决方案,就性能而言,我需要没有交叉/外部申请的解决方案。
答案 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;
这里的想法是为每个单独的Status
值(A或D)在整个表格中生成一个行号序列。然后,按照该行号顺序进行汇总,以将A和D记录放在一起。
答案 1 :(得分:1)
由于结果列Status1
和Status2
分别始终总是分别为“ 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记录。