Неочевидные факты про MIN и MAX

Простые функции. Кажется, что они находят просто минимум и максимум. Но есть и особенность их использования для интерпретации результатов. Об этом далее.

Неочевидные факты про MIN и MAX

А пока подписывайся на мой канал На связи: SQL Там я публикую посты про особенности и нюансы SQL. Этот канал про то, как не бояться баз данных, понимать, что такое JOIN, GROUP BY и почему NULL ≠ 0. Его я веду с нуля подписчиков. Присоединяйся!

MIN и MAX — не только про числа

Они работают с любыми типами данных:

  • датами (MIN(date) даст самую раннюю дату),
  • строками (MAX(name) вернёт последнюю в алфавитном порядке),
  • булевыми значениями (MIN(bool) — false, MAX(bool) — true).

Иногда этим можно ловко воспользоваться — например, чтобы узнать, есть ли хоть один true:

SELECT MAX(is_active) FROM users;

Если вернёт true — значит, кто-то активен. Красиво и лаконично.

MIN и MAX — не только агрегатные, но и оконные функции

Можно получить минимум или максимум в рамках окна, не теряя детализацию:

SELECT user_id, date, MAX(date) OVER (PARTITION BY user_id) AS last_activity FROM logins;

Так можно легко вытащить, когда пользователь последний раз заходил — без группировки и без JOIN.

MIN/MAX и NULL

Они игнорируют NULL.То есть если у тебя все значения NULL, то результат — NULL.
Это часто ломает аналитику, особенно при сравнении с COALESCE или при объединении данных.

SELECT MAX(COALESCE(score, 0)) -- вернёт 0, а не NULL

→ Иногда важно явно заменить NULL, чтобы не получить "пустой" результат.

MIN/MAX могут ускорить выборку

Если в таблице есть индекс по нужному полю —MIN() и MAX() используют только крайний элемент индекса.
Это значит, что:

SELECT MAX(price) FROM products;

может пройтись не по миллиону строк, а просто взять последнее значение из B-tree индекса. То есть — мгновенно.

Можно найти строку с минимальным/максимальным значением

Классическая боль аналитика: как вытащить не просто максимум, а всю строку, где он встретился.

💡 Один из лучших способов — оконная функция + фильтр:

SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn FROM employees ) t WHERE rn = 1;

→ Получаем сотрудника с максимальной зарплатой. Без подзапросов, без JOIN, без боли.

Неочевидный кейс: поиск экстремумов в группах

SELECT department, MIN(salary), MAX(salary) FROM employees GROUP BY department;

💬 Если хочешь больше таких разборов с реальными кейсами SQL без воды — подписывайся на мой Telegram 👉На связи: SQL
Там я рассказываю про SQL так, чтобы стало интересно даже тем, кто раньше его ненавидел 😄

Начать дискуссию