📁 Блок: SQL / MySQL / Оконные функции⏱️ Время изучения: ~90 мин🎯 Сложность: Продвинутая
⚡ Кратко: ошибки
Путать RANK и DENSE_RANK.
Забывать ORDER BY внутри OVER.
Фильтровать по псевдониму оконной функции в WHERE.
Ожидать от NTILE строго равных групп при любом числе строк.
1
Ошибка: путаница между RANK и DENSE_RANK
Если задача требует ранг без пропусков, а используется RANK(), результат будет неправильным.
-- Неправильно: здесь нужен DENSE_RANK
SELECT
product_name,
RANK() OVER (ORDER BY standard_cost DESC) AS cost_rank
FROM products;
Как исправить: заменить на DENSE_RANK(), когда не должно быть пропусков.
-- Правильно
SELECT
product_name,
DENSE_RANK() OVER (ORDER BY standard_cost DESC) AS cost_rank
FROM products;
2
Ошибка: отсутствие ORDER BY в окне
Ранжирующие функции не знают, в каком порядке нумеровать строки, если не задан ORDER BY.
-- Неправильно: синтаксическая ошибка или непредсказуемый результат
SELECT
product_name,
ROW_NUMBER() OVER () AS row_num
FROM products;
Как исправить: добавить ORDER BY внутри OVER.
-- Правильно
SELECT
product_name,
ROW_NUMBER() OVER (ORDER BY product_name) AS row_num
FROM products;
3
Ошибка: фильтрация по псевдониму оконной функции в WHERE
Оконные функции вычисляются после WHERE, поэтому их псевдоним нельзя использовать в фильтре.
-- Неправильно
SELECT
product_name,
DENSE_RANK() OVER (ORDER BY standard_cost DESC) AS cost_rank
FROM products
WHERE cost_rank <= 10;
Как исправить: обернуть запрос в подзапрос или CTE.
-- Правильно
SELECT product_name, cost_rank
FROM (
SELECT
product_name,
DENSE_RANK() OVER (ORDER BY standard_cost DESC) AS cost_rank
FROM products
) ranked
WHERE cost_rank <= 10;
4
Ошибка: неравные группы в NTILE
Если число строк не делится нацело на количество групп, NTILE добавляет «лишние» строки к первым группам. Это нормальное поведение, но о нём часто забывают.
-- При 5 строках и NTILE(4) группы будут: 2, 1, 1, 1 строка
SELECT
product_name,
list_price,
NTILE(4) OVER (ORDER BY list_price) AS price_group
FROM products;
Как исправить: если нужны строго равные группы, используйте ROW_NUMBER() и арифметику или пересмотрите число групп.