Лучший способ преобразовать список дат в DateFrom / DateTo диапазон

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

У меня есть таблица цен на товар в день. Вот пример того, как хранятся данные:

 Date       | Item  | Price
--------------------------
2020-01-01 | Item1 | 5.0
2020-01-02 | Item1 | 5.0
2020-01-03 | Item1 | 5.0
2020-01-04 | Item1 | 6.0
2020-01-05 | Item1 | 6.0
2020-01-06 | Item1 | 7.0
2020-01-07 | Item1 | 9.0
2020-01-08 | Item1 | 5.0
2020-01-09 | Item1 | 5.0
 

Я хочу «сжать» таблицу, сгруппировав данные по элементам и найдя минимальную и максимальную дату, когда цена была действительной.

Результат для приведенного выше примера должен быть следующим:

 DateFrom   | DateTo     | Item  | Price
----------------------------------------
2020-01-01 | 2020-01-03 | Item1 | 5.0
2020-01-04 | 2020-01-05 | Item1 | 6.0
2020-01-06 | 2020-01-06 | Item1 | 7.0
2020-01-07 | 2020-01-07 | Item1 | 9.0
2020-01-08 | 2020-01-09 | Item1 | 5.0
 

Как добиться этого в T-SQL?

Ответ №1:

Это тип проблемы пробелов и островов. Ключевым замечанием здесь является то, что вычитание перечисляемого ряда из даты является постоянным — когда значения одинаковы для смежных дат:

 select min(date), max(date), item, price
from (select t.*,
             row_number() over (partition by item, price order by date) as seqnum
      from t
     ) t
group by item, price,
         dateadd(day, -seqnum, date);
 

Обратите внимание, что эта формулировка предполагает, что у вас есть ровно одна дата на каждый день (для каждого элемента, я полагаю). Если это не так, задайте новый вопрос. Потребуется другой подход — и наилучший подход зависит от точного характера проблемы.

Комментарии:

1. Идеальный. какое элегантное решение! Спасибо!