TGViewer
SQL Ready | Базы Данных SQL Ready | Базы Данных @sql_ready · 17.5K subscribers
Post #1756 2.47K
Оконные агрегаты, как считать по группе и не терять строки!

Оконные функции удобны не только для ранжирования. Частая задача на практике — посчитать агрегаты по группе и при этом оставить каждую строку исходной таблицы.

Представим таблицу заказов:
orders(id, customer_id, amount, created_at)


Хотим увидеть все заказы и одновременно понимать, сколько денег каждый клиент потратил в сумме.

Первая мысль — посчитать через GROUP BY:
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id;


Да, сумму он посчитает. Но список заказов пропадёт — останется по одной строке на клиента.

Если коротко: GROUP BY считает по группе, но детали внутри группы выбрасывает.

Решение через оконную функцию:
SELECT
id,
customer_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM orders;


PARTITION BY customer_id разбивает строки на независимые окна по клиентам.
SUM(...) OVER (...) считает сумму внутри каждого окна, но строки не схлопывает — каждая остаётся на месте.

В результате каждая строка — отдельный заказ и total_amount — сумма всех заказов этого клиента.

Фильтрация по агрегату без GROUP BY — например, нужно выбрать только заказы тех клиентов, у которых суммарный оборот больше 1000:
SELECT *
FROM (
SELECT
*,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount
FROM orders
) t
WHERE total_amount > 1000;


Обратите внимание: фильтрация происходит уже после вычисления оконной функции. Никаких GROUP BY, никаких дополнительных JOIN.

Та же логика через JOIN (для сравнения):
SELECT o.*
FROM orders o
JOIN (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
) s ON s.customer_id = o.customer_id
WHERE s.total_amount > 1000;


Работает, но выглядит тяжелее: отдельный подзапрос, джойн, дублирование таблицы.

Можно посчитать сразу несколько агрегатов по тем же окнам:
SELECT
id,
customer_id,
amount,
SUM(amount) OVER (PARTITION BY customer_id) AS total_amount,
COUNT(*) OVER (PARTITION BY customer_id) AS orders_count
FROM orders;


Получаем и общую сумму, и количество заказов клиента — прямо в каждой строке.

🔥 Используйте оконные функции, когда нужно посчитать итог по группе, но не потерять сами строки. Это базовый приём аналитического SQL, который постоянно встречается в реальных задачах.

➡️ SQL Ready | #практика
  • 👍 19
  • ❤ 13
  • 🔥 8
More from @sql_ready
  1. Oct 7, 2026📂 Шпаргалка по паттернам распределённых систем! Например, Replication повышает доступност…
  2. Oct 6, 2026Проверяйте связи с учётом периода! В PostgreSQL 18 связь может учитывать ещё и период его…
  3. Oct 6, 2026⚡️5 фундаментальных курсов по ИБ по цене одного Это предложение для тех, кто готов войти в…
  4. Oct 6, 2026👍 Устройство PostgreSQL — подробная документация на русском языке! Материалы посвящены не…
  5. Oct 5, 2026COUNT(*) в PostgreSQL: MVCC, visibility map и стоимость выполнения! В PostgreSQL точный CO…
  6. Oct 5, 2026Как оплачивать зарубежные сервисы в 2026 году? Можно бегать между посредниками и бояться б…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →