CodeRang
Типовые задачи

PIVOT SQL: как превратить строки в столбцы

PIVOT SQL используют, когда значения из строк нужно разложить по отдельным колонкам. Разберём, как собрать такую сводную таблицу через условную агрегацию и FILTER.

Обновлено · Команда SQL Arena

Что потренируете

  • Разворачивать категории из строк в отдельные столбцы
  • Использовать SUM с FILTER в PostgreSQL
  • Строить тот же pivot через SUM(CASE ...)
  • Осознанно выбирать между NULL и 0
  • Возвращать широкую таблицу в длинный формат через UNION ALL

Пример задачи в тренажёре

Так выглядит задача в SQL Arena: условие, редактор, результат и схема базы.

Пред.След.Случайная
ЗаданиеОтправкиAI Mentor
Продажи магазинов по каналам в отдельных колонках

Для каждого магазина выведите shop_name, сумму продаж через web в web_sales и сумму продаж в магазине в store_sales. Магазины без продаж нужного типа тоже должны остаться в результате, а отсутствующая сумма должна отображаться как 0.

Запрос 1PostgreSQLv16
SELECT s.shop_name,
       COALESCE(SUM(sa.amount) FILTER (WHERE sa.channel = 'web'), 0) AS web_sales,
       COALESCE(SUM(sa.amount) FILTER (WHERE sa.channel = 'store'), 0) AS store_sales
FROM shops s
LEFT JOIN sales sa ON sa.shop_id = s.id
GROUP BY s.id, s.shop_name
ORDER BY s.shop_name;
Отправить
Результатshopssales
Ответ принят

Как работает PIVOT SQL на примере

Исходная таблица sales хранит канал в строках: web, store или partner. В итоговой сводной таблице web и store становятся отдельными колонками. PostgreSQL позволяет сделать это через агрегат с FILTER: SUM(amount) считает сумму, а FILTER ограничивает конкретный агрегат только строками нужного канала. Поэтому один GROUP BY создаёт сразу несколько показателей для каждой группы.

LEFT JOIN здесь важен не как тема сам по себе, а как способ сохранить магазины, для которых подходящих продаж нет. После группировки SUM по отсутствующим строкам возвращает NULL. COALESCE(..., 0) заменяет его на ноль, потому что в этой задаче ноль означает понятный бизнес-факт: продаж по каналу не было. Без COALESCE у Harbor был бы NULL в web_sales, а у Market — NULL в обеих колонках.

Тот же pivot можно написать переносимым способом: SUM(CASE WHEN channel = 'web' THEN amount ELSE 0 END). Такой вариант полезен в диалектах, где синтаксис FILTER недоступен или нежелателен. Но принцип одинаков: набор будущих колонок известен заранее, и для каждой категории создаётся отдельное условное агрегатное выражение.

SQLPostgreSQL v16
SELECT s.shop_name,
       COALESCE(SUM(sa.amount) FILTER (WHERE sa.channel = 'web'), 0) AS web_sales,
       COALESCE(SUM(sa.amount) FILTER (WHERE sa.channel = 'store'), 0) AS store_sales
FROM shops s
LEFT JOIN sales sa ON sa.shop_id = s.id
GROUP BY s.id, s.shop_name
ORDER BY s.shop_name;
Результат запроса
shop_nameweb_salesstore_sales
Central90110
Harbor0150
Market00
North12080
Park700

Ошибки при развороте строк в столбцы в SQL

01

Забыть ELSE 0 в CASE

В конструкции SUM(CASE WHEN ... THEN amount END) строки другой категории превращаются в NULL. Иногда это нормально, но при отсутствии совпадений весь SUM может остаться NULL. Если по смыслу нужен ноль, задайте ELSE 0 или используйте COALESCE вокруг агрегата.

02

Пытаться сделать динамические колонки обычным SELECT

SUM(CASE...) и FILTER хорошо работают, когда список будущих колонок заранее известен: например, web и store. Если категории появляются динамически и каждая должна становиться новой колонкой, статического SQL уже недостаточно — потребуется генерация запроса или другой формат результата.

03

Смешивать отсутствующее значение и ноль

NULL и 0 не всегда означают одно и то же. Ноль может означать, что показатель действительно измерен и равен нулю, а NULL — что данных нет или показатель неприменим. Перед COALESCE стоит определить, какое значение соответствует смыслу отчёта.

Задачи по теме в тренажёре

Трек «SQL с нуля → Аналитик»

После простого pivot удобно закрепить приём на прикладных сводках: посчитать итоговый баланс по счетам, разнести платежи по способам оплаты или собрать показатели доставки по магазинам. Несколько таких Easy-задач доступны бесплатно. Если хочется пройти путь последовательно от базовых конструкций к аналитическим задачам, продолжайте в треке «SQL с нуля → Аналитик».

Частые вопросы

Что такое PIVOT SQL?

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

Как сделать PIVOT в SQL?

Способ зависит от СУБД. В диалектах без отдельного оператора PIVOT строки можно развернуть через условную агрегацию: SUM или COUNT сочетают с FILTER либо CASE для каждой будущей колонки.

Как превратить строки в столбцы в SQL?

Нужно определить значения, которые станут колонками, сгруппировать данные по оставшимся полям и вычислить отдельный агрегат для каждого значения. Например, суммы продаж по каналам можно вывести отдельными колонками web и store.

Чем PIVOT отличается от GROUP BY в SQL?

GROUP BY объединяет строки в группы и позволяет считать агрегаты, но сам по себе не превращает значения категорий в отдельные колонки. PIVOT или условная агрегация используют GROUP BY как часть решения, добавляя отдельное выражение для каждой выводимой категории.

Попрактикуйтесь с PIVOT SQL на задачах

В SQL Arena — 1 192 задачи с автопроверкой. Для PostgreSQL, MySQL, ClickHouse и BigQuery доступны отдельные песочницы, ER-диаграммы и EXPLAIN. Бесплатно без карты можно решать 292 задачи на всех четырёх диалектах.

Решать задачи в SQL Arena