Поскольку столбцы результата 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))
Изначально он получает все записи из таблицыгде status равен 'A' (используется выражение D.[Status] = 'A'
в предложении WHERE).
Для каждой найденной записи он объединяет дату следующей записи со статусом A (табличное выражение с псевдонимом NextA
)и дата последней записи со статусом D, которая идет непосредственно перед следующей A-записью, но после текущей A-записи (табличное выражение с псевдонимом LastDBeforeNextA
).
Результаты действительны, когда D-записьнайдено (выражение [NextA].[Dt] > [LastDBeforeNextA].[Dt]
в предложении WHERE) или когда еще нет D-записи (выражение [LastDBeforeNextA].[Dt] IS NULL
в предложении WHERE).Однако в последнем случае вам нужно получить последнюю A-запись (выражение [NextA].[Dt] IS NULL
в предложении WHERE), поскольку после последней D-записи может быть несколько A-записей.