Найдите Пики Данных По Значениям И Суммируйте Их За Период Времени В SQL

#sql #sql-server #azure-data-factory

Вопрос:

Для SQL-запроса/хранимой процедуры я ищу сумму пиков заданных значений по типу за определенный период времени. Кроме того, если в течение данного периода времени пик не имеет тенденции к снижению, его не следует учитывать.

Данные, например:

Тип Сумма Дата
ААА 10 2021-07-11
ААА 15 2021-07-11
ААА 20 2021-07-11
ААА 25 2021-07-11 *Нужен этот пик
ААА 20 2021-07-11
ААА 15 2021-07-11
ААА 10 2021-07-11
ААА 15 2021-07-11
ААА 20 2021-07-11
ААА 25 2021-07-11
ААА 30 2021-07-11 *Нужно добавить этот пик к предыдущему пику
ААА 20 2021-07-11
ААА 15 2021-07-11
ААА 10 2021-07-11
BBB 10 2021-07-11
BBB 20 2021-07-11
BBB 30 2021-07-11 *Нужен этот пик
BBB 20 2021-07-11
BBB 10 2021-07-11
ССС 10 2021-07-11
ССС 20 2021-07-11
ССС 30 2021-07-11
ССС 20 2021-07-11
ССС 10 2021-07-11
ССС 20 2021-07-11
ССС 30 2021-07-11
ССС 40 2021-07-11 *Этот пик не будет учитываться, потому что нисходящий тренд произойдет на следующий день
ССС 30 2021-07-12
ССС 20 2021-07-12
ССС 10 2021-07-12

Результаты за данный день 2021-07-11 должны быть:

Тип Весь
ААА 55
BBB 30

(ССС не включен, так как на данную дату не было нисходящего тренда)

Я даже не совсем уверен, с чего начать, за исключением, возможно, получения значения каждой строки, у которой следующая строка меньше (начинается нисходящий тренд).

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

1. . . Таблицы SQL представляют собой неупорядоченные наборы. Без упорядочения строк (возможно, с использованием компонента времени date ) на этот вопрос невозможно ответить.

Ответ №1:

Позвольте мне предположить, что в вашей date колонке есть временная составляющая. На самом деле вам нужен явный порядок строк, а даты недостаточно.

Если это так, вы можете использовать lead() и lag() :

 select t.*
from (select t.*,
             lag(amount) over (partition by type, convert(date, date) order by date) as prev_amount,
             lead(amount) over (partition by type, convert(date, date) order by date) as next_amount
      from t
     ) t
where prev_amount < amount and amount > next_amount;
 

Редактировать:

Для окончательного согласования:

 select type, sum(amount)
from (select t.*,
             lag(amount) over (partition by type, convert(date, date) order by date) as prev_amount,
             lead(amount) over (partition by type, convert(date, date) order by date) as next_amount
      from t
     ) t
where prev_amount < amount and amount > next_amount;
group by type;
 

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

1. На самом деле это метка времени, а не просто дата. Извините, я пытался упростить пример. Я задавался вопросом об использовании подхода с запаздыванием и опережением, но не был уверен. Как я могу убедиться, что получаю каждый набор (или каждый «Тип» в примере) и суммирую эти квалифицированные пики?

2. Не следует ли скорее провести второе сравнение amount > next_amount , если мы ищем локальный максимум?

3. @GordonLinoff, это очень полезно. Большое спасибо.

Ответ №2:

Учитывая текущую структуру таблицы, это невозможно. Вам понадобится, по крайней мере, еще один столбец, чтобы указать порядок каждой записи. В противном случае запрос не гарантирует

 AAA 10  2021-07-11
 

всегда будет приходить раньше

 AAA 15  2021-07-11
 

Нет никакого индикатора, почему второе позже первого.

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

1. В реляционной базе данных нет встроенного порядка-вы должны каким — то образом добавить ее сами.

2. Да, в этом есть полный смысл. На самом деле это метка времени, а не просто дата. Я пытался упростить пример, но вы абсолютно правы.