Почему поведение min() отличается от поведения max()?
Select
max(My_Date) over (order by My_Date) as Max_Datum
, min(My_Date) over (order by My_Date) as Min_Datum
From
(
Select dateadd(m,-1,getdate()) as My_Date
Union all
Select getdate() as My_Date
Union all
Select dateadd(m,1,getdate()) as My_Date
Union all
Select dateadd(m,2,getdate()) as My_Date
) t1
Результат:
Max_Datum Min_Datum
2024-08-02 16:20:39.733 2024-08-02 16:20:39.733
2024-09-02 16:20:39.733 2024-08-02 16:20:39.733
2024-10-02 16:20:39.733 2024-08-02 16:20:39.733
2024-11-02 16:20:39.733 2024-08-02 16:20:39.733
Что вы пытаетесь найти для начала? Какие ценности вы ожидали? Если вы хотите найти общую максимальную или минимальную дату, вам не нужен OVER
. Используйте SELECT MIN(My_Date), MAX(My_Date) FROM (...)
Время педантичных комментариев: Datum — это единственная форма слова «данные», оно не относится конкретно к дате!
@DavidG6 Извините, я адаптировал запрос с немецкого. В Германии мы используем «Datum» для обозначения даты. Морген не может найти датум? --> Какое число завтра?
Ха, честное слово, я откажусь от своего педантичности!
Было бы полезно, если бы вы конкретно объяснили, какого поведения ожидает Исния.
Проблема не в функциях, а в вашем предложении OVER
. Вы добавили предложение OVER
с предложением ORDER BY My_Date
, которое, согласно документации , по умолчанию соответствует окну RANGE UNBOUNDED PRECEDING AND CURRENT ROW
. В результате значение MAX
всегда будет значением текущей строки, потому что именно в этом порядке расположены данные.
Возьмем, к примеру, следующие упрощенные данные:
Теперь предположим, что у вас есть аналогичный запрос:
SELECT MIN(SomeNumber) OVER (ORDER BY SomeNumber) AS MinSomeNumber,
MAX(SomeNumber) OVER (ORDER BY SomeNumber) AS MaxSomeNumber
FROM dbo.SomeTable
ORDER BY ID;
Это приведет к результатам:
Фактически в каждой строке вы задаете следующее:
Итак, вы можете видеть, что MAX
будет отличаться, а MIN
— нет.
Вероятно, вы хотите изменить ORDER
, указать окно как весь набор данных или не указывать окно:
SELECT MIN(SomeNumber) OVER (ORDER BY SomeNumber) AS MinSomeNumber,
MAX(SomeNumber) OVER (ORDER BY SomeNumber DESC) AS MaxSomeNumber,
MIN(SomeNumber) OVER (ORDER BY SomeNumber ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MinSomeNumber,
MAX(SomeNumber) OVER (ORDER BY SomeNumber ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MaxSomeNumber,
MIN(SomeNumber) OVER () AS MinSomeNumber,
MAX(SomeNumber) OVER () AS MaxSomeNumber
FROM dbo.SomeTable;
Последнее, вероятно, имеет здесь наибольший «смысл», поскольку размещение данных для MIN
/MAX
в порядке значения, для которого вы получаете MIN
/MAX
, ничего не дает. Если бы вы упорядочивали по другому столбцу, это имело бы больше смысла.
Функция МИН смотрит назад (включая текущую строку и все предыдущие строки), поэтому она продолжает возвращать самую раннюю дату, которую она видела.
Функция MAX также смотрит назад, но продолжает обновляться до последнего максимального значения, с которым она столкнулась.
MAX(): при перемещении по строкам он просматривает текущую строку и все строки перед ней. Он всегда выбирает самую большую (последнюю) дату, которую он когда-либо видел.
MIN(): при перемещении по строкам он также просматривает текущую строку и все строки перед ней. Но он всегда выбирает самую маленькую (самую раннюю) дату, которую он видел до сих пор.
Ваши данные У вас есть такие даты:
2024-08-02 2024-09-02 2024-10-02 2024-11-02 Для МАКС():
Начинается со 2 августа 2024 г. Переходит к 2 сентября 2024 г.: «Что больше? 02 сентября 2024 г. или 02 августа 2024 г.?» Он сохраняется 2 сентября 2024 г.
Далее идет 2024-10-02: «Что больше? 2024-10-02 или 2024-09-02?» Он сохраняется 02.10.2024.
Наконец, 02.11.2024: «Что больше? 02.11.2024 или 02.10.2024?» Он сохраняется 02.11.2024. Для МИН():
Начинается со 2 августа 2024 г. Переходит к 2 сентября 2024 г.: «Что меньше? 02 сентября 2024 г. или 02 августа 2024 г.?» Он сохраняется 2 августа 2024 г.
Далее следует 02.10.2024: «Что меньше? 02.10.2024 или 02.08.2024?» Он все еще сохраняется 2 августа 2024 г.
Наконец, 02.11.2024: «Что меньше? 02.11.2024 или 02.08.2024?» Он все еще сохраняется 2 августа 2024 г.
Подводя итог, можно сказать, что и min(), и max() просматривают все предыдущие строки в упорядоченном окне, но min() сохраняет самую раннюю дату, а max() обновляет до самой последней. Вот почему вы видите описанное вами поведение.
Функции MAX
/MIN
не имеют никакого отношения к проблеме, это оконное управление. LAST_VALUE
/FIRST_VALUE
демонстрируют такое же поведение. AVG
бы. Любая оконная функция с ORDER BY
подойдет, потому что проблема в окне, а не в функции.
Честно говоря, для меня это немного напоминает LLM.
Поскольку рамка окна по умолчанию заканчивается в текущей строке, как только вы добавляете порядок. Таким образом, максимум — не видеть более поздние даты, если вы не добавите
rows between unbounded preceding and unbounded following