Это похоже на проблему "пробелов и островов" с "топ-1-на-группу" сверху после обнаружения групп / островов.
Вот один из способов сделать это.
Пример данных
CREATE TABLE #temptable ( Descr varchar(50), [Price] int, dt date )
INSERT INTO #temptable
VALUES
( 'Active', 799900, N'2019-02-27T00:00:00' ),
( 'Unknown', 629900, N'2014-09-24T00:00:00' ),
( 'Unknown', 629900, N'2014-09-12T00:00:00' ),
( 'Sold', 625900, N'2014-09-08T00:00:00' ),
( 'Unknown', 629900, N'2014-08-10T00:00:00' ),
( 'Active', 629900, N'2014-07-27T00:00:00' ),
( 'Pending', 629900, N'2014-07-25T00:00:00' ),
( 'Pending', 629900, N'2014-07-24T00:00:00' ),
( 'Unknown', 629900, N'2014-07-20T00:00:00' ),
( 'Active', 629900, N'2014-07-16T00:00:00' ),
( 'Active', 629900, N'2014-07-15T00:00:00' ),
( 'Taking Backup Offers', 629900, N'2014-07-11T00:00:00' ),
( 'Active', 629900, N'2014-06-28T00:00:00' ),
( 'Active', 629900, N'2014-06-27T00:00:00' ),
( 'Taking Backup Offers', 629900, N'2014-06-27T00:00:00' ),
( 'Active', 629900, N'2014-06-23T00:00:00' ),
( 'Active', 629900, N'2014-06-11T00:00:00' ),
( 'Active', 629900, N'2014-06-10T00:00:00' ),
( 'Sold', 570000, N'2010-01-22T00:00:00' ),
( 'Sold', 288000, N'2000-09-01T00:00:00' );
Запрос
WITH
CTE_RN
AS
(
SELECT
*
,ROW_NUMBER() OVER (ORDER BY dt DESC) AS rn1
,ROW_NUMBER() OVER (PARTITION BY Descr ORDER BY dt DESC) AS rn2
FROM #temptable
)
,CTE_Groups
AS
(
SELECT
*
,rn1 - rn2 AS Groups
,ROW_NUMBER() OVER (PARTITION BY Descr, rn1 - rn2 ORDER BY dt) AS rn
FROM CTE_RN
)
SELECT Descr, Price, dt
FROM CTE_Groups
WHERE rn = 1
ORDER BY dt DESC;
Результат
+----------------------+--------+------------+
| Descr | Price | dt |
+----------------------+--------+------------+
| Active | 799900 | 2019-02-27 |
| Unknown | 629900 | 2014-09-12 |
| Sold | 625900 | 2014-09-08 |
| Unknown | 629900 | 2014-08-10 |
| Active | 629900 | 2014-07-27 |
| Pending | 629900 | 2014-07-24 |
| Unknown | 629900 | 2014-07-20 |
| Active | 629900 | 2014-07-15 |
| Taking Backup Offers | 629900 | 2014-07-11 |
| Taking Backup Offers | 629900 | 2014-06-27 |
| Active | 629900 | 2014-06-27 |
| Active | 629900 | 2014-06-10 |
| Sold | 288000 | 2000-09-01 |
+----------------------+--------+------------+
Обратите внимание, что, поскольку есть две строки с одинаковой датой 2014-06-27
, сервер может вернуть их, как вы показали в ожидаемом результате, или он может вернуть их, как показано здесь. Скорее всего, у вас есть столбец ID
, поэтому используйте его для разрешения сортировки.
Чтобы понять, как это работает, запустите промежуточный запрос и изучите его результат (столбцы rn1, rn2, Groups, rn
).
WITH
CTE_RN
AS
(
SELECT
*
,ROW_NUMBER() OVER (ORDER BY dt DESC) AS rn1
,ROW_NUMBER() OVER (PARTITION BY Descr ORDER BY dt DESC) AS rn2
FROM #temptable
)
,CTE_Groups
AS
(
SELECT
*
,rn1 - rn2 AS Groups
,ROW_NUMBER() OVER (PARTITION BY Descr, rn1 - rn2 ORDER BY dt) AS rn
FROM CTE_RN
)
SELECT *
FROM CTE_Groups
ORDER BY dt DESC;
Результат
+----------------------+--------+------------+-----+-----+--------+----+
| Descr | Price | dt | rn1 | rn2 | Groups | rn |
+----------------------+--------+------------+-----+-----+--------+----+
| Active | 799900 | 2019-02-27 | 1 | 1 | 0 | 1 |
| Unknown | 629900 | 2014-09-24 | 2 | 1 | 1 | 2 |
| Unknown | 629900 | 2014-09-12 | 3 | 2 | 1 | 1 |
| Sold | 625900 | 2014-09-08 | 4 | 1 | 3 | 1 |
| Unknown | 629900 | 2014-08-10 | 5 | 3 | 2 | 1 |
| Active | 629900 | 2014-07-27 | 6 | 2 | 4 | 1 |
| Pending | 629900 | 2014-07-25 | 7 | 1 | 6 | 2 |
| Pending | 629900 | 2014-07-24 | 8 | 2 | 6 | 1 |
| Unknown | 629900 | 2014-07-20 | 9 | 4 | 5 | 1 |
| Active | 629900 | 2014-07-16 | 10 | 3 | 7 | 2 |
| Active | 629900 | 2014-07-15 | 11 | 4 | 7 | 1 |
| Taking Backup Offers | 629900 | 2014-07-11 | 12 | 1 | 11 | 1 |
| Active | 629900 | 2014-06-28 | 13 | 5 | 8 | 2 |
| Active | 629900 | 2014-06-27 | 14 | 6 | 8 | 1 |
| Taking Backup Offers | 629900 | 2014-06-27 | 15 | 2 | 13 | 1 |
| Active | 629900 | 2014-06-23 | 16 | 7 | 9 | 3 |
| Active | 629900 | 2014-06-11 | 17 | 8 | 9 | 2 |
| Active | 629900 | 2014-06-10 | 18 | 9 | 9 | 1 |
| Sold | 570000 | 2010-01-22 | 19 | 2 | 17 | 2 |
| Sold | 288000 | 2000-09-01 | 20 | 3 | 17 | 1 |
+----------------------+--------+------------+-----+-----+--------+----+
Слово предостережения
Добавление ORDER BY dt DESC, rn1 ASC
к основному запросу не гарантирует, что он даст ожидаемый результат. rn1
со значениями 14 и 15 можно поменять местами, поскольку их дата (2014-06-27
) одинакова. Если даты не уникальны, вам нужен дополнительный уникальный столбец, чтобы сортировка была стабильной и предсказуемой. В данных примера таких столбцов нет, но обычно таблицы имеют уникальный первичный ключ, поэтому его следует использовать.
Итак, для ваших примеров данных вполне нормально, чтобы запрос приводил такой результат:
Intermediate
+----------------------+--------+------------+-----+-----+--------+----+
| Descr | Price | dt | rn1 | rn2 | Groups | rn |
+----------------------+--------+------------+-----+-----+--------+----+
| Active | 799900 | 2019-02-27 | 1 | 1 | 0 | 1 |
| Unknown | 629900 | 2014-09-24 | 2 | 1 | 1 | 2 |
| Unknown | 629900 | 2014-09-12 | 3 | 2 | 1 | 1 |
| Sold | 625900 | 2014-09-08 | 4 | 1 | 3 | 1 |
| Unknown | 629900 | 2014-08-10 | 5 | 3 | 2 | 1 |
| Active | 629900 | 2014-07-27 | 6 | 2 | 4 | 1 |
| Pending | 629900 | 2014-07-25 | 7 | 1 | 6 | 2 |
| Pending | 629900 | 2014-07-24 | 8 | 2 | 6 | 1 |
| Unknown | 629900 | 2014-07-20 | 9 | 4 | 5 | 1 |
| Active | 629900 | 2014-07-16 | 10 | 3 | 7 | 2 |
| Active | 629900 | 2014-07-15 | 11 | 4 | 7 | 1 |
| Taking Backup Offers | 629900 | 2014-07-11 | 12 | 1 | 11 | 1 |
| Active | 629900 | 2014-06-28 | 13 | 5 | 8 | 1 |
| Taking Backup Offers | 629900 | 2014-06-27 | 14 | 2 | 12 | 1 |
| Active | 629900 | 2014-06-27 | 15 | 6 | 9 | 4 |
| Active | 629900 | 2014-06-23 | 16 | 7 | 9 | 3 |
| Active | 629900 | 2014-06-11 | 17 | 8 | 9 | 2 |
| Active | 629900 | 2014-06-10 | 18 | 9 | 9 | 1 |
| Sold | 570000 | 2010-01-22 | 19 | 2 | 17 | 2 |
| Sold | 288000 | 2000-09-01 | 20 | 3 | 17 | 1 |
+----------------------+--------+------------+-----+-----+--------+----+
Final
+----------------------+--------+------------+
| Descr | Price | dt |
+----------------------+--------+------------+
| Active | 799900 | 2019-02-27 |
| Unknown | 629900 | 2014-09-12 |
| Sold | 625900 | 2014-09-08 |
| Unknown | 629900 | 2014-08-10 |
| Active | 629900 | 2014-07-27 |
| Pending | 629900 | 2014-07-24 |
| Unknown | 629900 | 2014-07-20 |
| Active | 629900 | 2014-07-15 |
| Taking Backup Offers | 629900 | 2014-07-11 |
| Active | 629900 | 2014-06-28 |
| Taking Backup Offers | 629900 | 2014-06-27 |
| Active | 629900 | 2014-06-10 |
| Sold | 288000 | 2000-09-01 |
+----------------------+--------+------------+
Как видите, этот результат отличается от первого результата, потому что есть две строки с одинаковой датой, и механизм может свободно размещать их в любом порядке.
В этом результате есть Active
с другой датой 2014-06-28
, потому что Active
с 2014-06-27
оказалось ниже Taking Backup Offers 2014-06-27
.