[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-sql-chto-takoe-okonnye-funktsii-window-functions":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":15,"progress":16,"seo":17},874,"chto-takoe-okonnye-funktsii-window-functions",25,"sql","SQL","🗃️","Что такое оконные функции (Window Functions)?","Оконные функции (Window Functions) — функции, которые выполняют вычисления над набором строк, связанных с текущей строкой, без сворачивания результата в одну строку. В отличие от агрегатных функций с `GROUP BY`, каждая строка сохраняется в результате, а к ней добавляется вычисленное значение.\n\n> **Аналогия из жизни:** представьте таблицу зарплат в компании. `GROUP BY` сложит все зарплаты отдела и покажет одну строку. Оконная функция покажет каждого сотрудника, но рядом допишет, какая средняя зарплата в его отделе.\n\n### Общий синтаксис\n\n```sql\nфункция() OVER (\n    [PARTITION BY столбец_разделения]\n    [ORDER BY столбец_сортировки]\n    [ROWS | RANGE BETWEEN начало AND конец]\n)\n```\n\n- `PARTITION BY` — разделяет набор строк на группы (аналог `GROUP BY`, но без сворачивания)\n- `ORDER BY` — определяет порядок строк внутри каждого раздела\n- `ROWS\u002FRANGE BETWEEN` — определяет рамку (frame) — подмножество строк, участвующих в вычислении\n\n### Функции ранжирования\n\n| Функция | Описание |\n|---------|---------|\n| `ROW_NUMBER()` | Уникальный номер строки |\n| `RANK()` | Ранг с пропуском позиций |\n| `DENSE_RANK()` | Ранг без пропуска позиций |\n| `NTILE(n)` | Деление на n групп |\n\n```sql\nSELECT\n    name, department, salary,\n    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num,\n    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk,\n    DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rnk\nFROM employees;\n```\n\n### Функции смещения\n\n| Функция | Описание |\n|---------|---------|\n| `LAG(col, n, default)` | Значение из предыдущей строки (на n позиций назад) |\n| `LEAD(col, n, default)` | Значение из следующей строки (на n позиций вперёд) |\n| `FIRST_VALUE(col)` | Первое значение в рамке окна |\n| `LAST_VALUE(col)` | Последнее значение в рамке окна |\n\n```sql\nSELECT\n    name, salary,\n    LAG(salary, 1, 0) OVER (ORDER BY hire_date) AS prev_salary,\n    salary - LAG(salary, 1, 0) OVER (ORDER BY hire_date) AS salary_diff\nFROM employees;\n```\n\n### Агрегатные функции как оконные\n\n`SUM`, `AVG`, `COUNT`, `MIN`, `MAX` могут использоваться для вычисления накопительных (running) итогов:\n\n```sql\nSELECT\n    order_date, amount,\n    SUM(amount) OVER (ORDER BY order_date) AS running_total,\n    AVG(amount) OVER (ORDER BY order_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg_3\nFROM orders;\n```\n\n### Рамки окна (Window Frame)\n\n```sql\nROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW   -- от начала до текущей строки\nROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING            -- 3 строки до и после\nROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING    -- от текущей до конца\nROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING  -- все строки раздела\n```\n\nРазличие `ROWS` и `RANGE`: `ROWS` работает с физическими строками, `RANGE` — с логическими значениями (строки с одинаковым значением `ORDER BY` считаются одной «позицией»).\n\n### Практический пример: топ-3 сотрудника по зарплате в каждом отделе\n\n```sql\nSELECT * FROM (\n    SELECT\n        name, department, salary,\n        DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rnk\n    FROM employees\n) ranked\nWHERE rnk \u003C= 3;\n```\n\n### Важное\n\n- Оконные функции выполняются после `WHERE`, `GROUP BY`, `HAVING`, но до `ORDER BY` и `LIMIT`\n- Оконные функции нельзя использовать в `WHERE` и `HAVING` — для этого нужен подзапрос или CTE\n- Именованное окно позволяет избежать дублирования: `WINDOW w AS (PARTITION BY department ORDER BY salary)`, затем `OVER w`\n- По умолчанию, если указан `ORDER BY` без рамки, PostgreSQL использует `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`\n\n### Частые ошибки\n\n- Путаница между `RANK()` и `DENSE_RANK()` — забывают, что `RANK()` пропускает позиции\n- Использование `LAST_VALUE()` без явного указания рамки — по умолчанию рамка заканчивается на текущей строке. Нужно явно указать `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`\n- Попытка фильтрации по оконной функции в `WHERE` вместо оборачивания в подзапрос\n- Забывают `PARTITION BY` и получают вычисление по всему набору данных вместо групп\n\n> **На собеседовании:** покажите, что понимаете отличие от `GROUP BY` — оконные функции не сворачивают строки. Назовите 3-4 функции и приведите пример с `PARTITION BY`. Частая ошибка — не знать про рамки окна (`ROWS`\u002F`RANGE`) и их влияние на результат.","","middle",[7],[],null,{"title":18,"description":19,"ogTitle":18,"ogDescription":20,"keywords":21,"schemaAnswer":22,"featuredSnippetReady":23},"Что такое оконные функции (Window Functions)? — Gymterview","Оконные функции (Window Functions) — функции, которые выполняют вычисления над набором строк, связанных с текущей строкой, без сворачивания результата в одну ст","Оконные функции (Window Functions) — функции, которые выполняют вычисления над набором строк, связанных с текущей строко",[7,13],"Оконные функции (Window Functions) — функции, которые выполняют вычисления над набором строк, связанных с текущей строкой, без сворачивания результата в одну строку. В отличие от агрегатных функций с `GROUP BY`, каждая строка сохраняется в результате, а к ней добавляется вычисленное значение.",true]