Это классический запрос greatest-n-per-group
. Я бы использовал CROSS APPLY
здесь.
Удостоверьтесь, что у вас есть индекс на (GroupID, dt, ID)
.
Возможно, у вас есть таблица Groups
, которая имеет список всех GroupIDs
. В нижеприведенном запросе я использую CTE для получения списка всех отличных GroupIDs
.
Выборочные данные
Я добавил несколько строк, чтобы показать, как запрос работает в различных случаях.
DECLARE @VarDate date = '2011-07-31';
DECLARE @T TABLE (ID int, GroupID int, Status varchar(2), dt date);
INSERT INTO @T (ID, GroupID, Status, dt) VALUES
(2, 1, 'S1', '2011-07-29'),
(3, 1, 'S2', '2011-07-30'),
(9, 1, 'S1', '2011-08-02'),
(7, 1, 'S1', '2011-08-03'),
(8, 1, 'S1', '2011-08-04'),
(1, 2, 'S1', '2011-07-28'),
(4, 2, 'S2', '2011-07-30'),
(5, 2, 'S3', '2011-08-01'),
(6, 3, 'S1', '2011-08-02'),
(11, 4, 'S1', '2011-08-04'),
(12, 4, 'S2', '2011-08-02'),
(13, 4, 'S3', '2011-08-02'),
(21, 4, 'S1', '2011-07-04'),
(22, 4, 'S2', '2011-07-04'),
(23, 4, 'S3', '2011-07-04'),
(31, 5, 'S1', '2011-07-31'),
(32, 5, 'S2', '2011-07-31'),
(33, 5, 'S3', '2011-07-31'),
(34, 5, 'S1', '2011-07-31'),
(35, 5, 'S2', '2011-07-31'),
(36, 5, 'S3', '2011-07-31'),
(41, 6, 'S1', '2011-07-31');
Запрос
Для каждого GroupID
мы находим верхние и нижние строки с помощью CROSS APPLY
, то UNION ALL
верхних и нижних результатов вместе.
WITH
CTE_Groups
AS
(
SELECT DISTINCT GroupID
FROM @T
)
SELECT
CA.ID
,Groups.GroupID
,CA.Status
,CA.dt
FROM
CTE_Groups AS Groups
CROSS APPLY
(
SELECT TOP(1)
T.ID
,T.Status
,T.dt
FROM @T AS T
WHERE
T.GroupID = Groups.GroupID
AND T.dt >= @VarDate
ORDER BY T.dt, ID
) AS CA
UNION ALL
SELECT
CA.ID
,Groups.GroupID
,CA.Status
,CA.dt
FROM
CTE_Groups AS Groups
CROSS APPLY
(
SELECT TOP(1)
T.ID
,T.Status
,T.dt
FROM @T AS T
WHERE
T.GroupID = Groups.GroupID
AND T.dt <= @VarDate
ORDER BY T.dt DESC, ID DESC
) AS CA
ORDER BY GroupID, dt;
Результат
+----+---------+--------+------------+
| ID | GroupID | Status | dt |
+----+---------+--------+------------+
| 3 | 1 | S2 | 2011-07-30 |
| 9 | 1 | S1 | 2011-08-02 |
| 4 | 2 | S2 | 2011-07-30 |
| 5 | 2 | S3 | 2011-08-01 |
| 6 | 3 | S1 | 2011-08-02 |
| 23 | 4 | S3 | 2011-07-04 |
| 12 | 4 | S2 | 2011-08-02 |
| 31 | 5 | S1 | 2011-07-31 |
| 36 | 5 | S3 | 2011-07-31 |
| 41 | 6 | S1 | 2011-07-31 |
| 41 | 6 | S1 | 2011-07-31 |
+----+---------+--------+------------+
Я использую SQL Server. И сопоставить внешнюю дату источника: 7/31/2011 –