
При работе с аналитическими данными часто возникает задача преобразовать строки в столбцы или наоборот. В SQL это называют поворотом таблицы или операцией pivot/unpivot. Такая трансформация позволяет упрощать построение отчетов, сводных таблиц и агрегированных выборок.
Для поворота таблицы применяются разные подходы: использование оператора PIVOT в T-SQL, конструкции CASE WHEN в PostgreSQL и MySQL, а также функций агрегирования с фильтрацией по условиям. Конкретный метод зависит от используемой СУБД и требований к результату.
Важно понимать, что «перевернуть» таблицу можно двумя способами: собрать данные в компактный вид, сгруппировав значения по категориям, или развернуть их, превратив столбцы в строки. Эти операции полезны при создании универсальных отчетов, где структура таблицы должна соответствовать бизнес-логике, а не исходному формату данных.
Что значит «перевернуть» таблицу и в каких случаях это нужно
Под «переворотом» таблицы в SQL понимают трансформацию строк в столбцы или наоборот. Такой приём необходим, когда текущая структура данных не подходит для анализа или визуализации. Например, агрегированные значения удобно хранить в строках, но для отчёта их часто требуется отразить по столбцам.
Рассмотрим исходный набор данных:
| Месяц | Категория | Сумма |
|---|---|---|
| Январь | Продажи | 1200 |
| Январь | Возвраты | 100 |
| Февраль | Продажи | 1500 |
| Февраль | Возвраты | 200 |
Для аналитика удобнее видеть эти данные так, чтобы каждая категория была отдельным столбцом:
| Месяц | Продажи | Возвраты |
|---|---|---|
| Январь | 1200 | 100 |
| Февраль | 1500 | 200 |
Переворот необходим в случаях: формирование сводных отчётов, подготовка данных для BI-систем, ускорение сравнения по категориям, приведение таблицы к формату, ожидаемому внешними инструментами или API.
Использование оператора PIVOT для преобразования строк в столбцы
Оператор PIVOT применяется в SQL Server и Oracle для преобразования значений одного столбца в названия новых столбцов, выполняя при этом агрегирование данных. Это позволяет быстро получить сводную таблицу без использования сложных конструкций CASE.
Пример: имеется таблица Продажи с колонками Год, Месяц и Сумма. Чтобы получить отчет с суммой продаж по каждому месяцу в отдельных столбцах, используется следующий запрос:
SELECT Год, [1] AS Январь, [2] AS Февраль, [3] AS Март
FROM Продажи
PIVOT (
SUM(Сумма)
FOR Месяц IN ([1], [2], [3])
) AS p;
В блоке SUM(Сумма) указывается агрегатная функция, необходимая для обработки дублирующихся строк. Ключевое выражение FOR Месяц IN (...) определяет список значений, которые будут преобразованы в названия новых столбцов.
Если необходимо динамически генерировать список столбцов, используют динамический SQL: сначала формируют строку с перечислением уникальных значений, затем подставляют её в оператор PIVOT. Это удобно при анализе показателей с непредсказуемыми категориями, например, списком регионов или новых продуктов.
Применение оператора UNPIVOT для обратного преобразования
Оператор UNPIVOT используется для преобразования столбцов в строки, что удобно при работе с денормализованными данными. В отличие от PIVOT, который агрегирует значения, UNPIVOT раскладывает данные обратно в длинный формат.
Пример: имеется таблица с продажами по кварталам:
CREATE TABLE Sales (
Product NVARCHAR(50),
Q1 INT,
Q2 INT,
Q3 INT,
Q4 INT
);
Для преобразования столбцов Q1–Q4 в строки можно использовать следующий запрос:
SELECT Product, Quarter, Amount
FROM Sales
UNPIVOT (
Amount FOR Quarter IN (Q1, Q2, Q3, Q4)
) AS u;
В результате данные будут представлены в формате: Product | Quarter | Amount. Такой вид удобен для последующего анализа, объединения с другими таблицами и применения агрегирующих функций.
Рекомендация: при работе с UNPIVOT всегда задавайте псевдонимы для новых столбцов, чтобы исключить неоднозначность в именах. Если требуется обработка значений NULL, используйте функцию COALESCE для их замены на нули или другие значения до выполнения преобразования.
Как перевернуть таблицу с помощью агрегирующих функций и CASE
При отсутствии встроенного оператора PIVOT в СУБД можно развернуть таблицу с помощью комбинации агрегирующих функций и выражения CASE. Такой подход позволяет превратить значения в строках в отдельные столбцы.
Пример: есть таблица продаж с полями manager, month, amount. Нужно вывести итоги по каждому менеджеру в разрезе месяцев.
SELECT
manager,
SUM(CASE WHEN month = 'Январь' THEN amount ELSE 0 END) AS Январь,
SUM(CASE WHEN month = 'Февраль' THEN amount ELSE 0 END) AS Февраль,
SUM(CASE WHEN month = 'Март' THEN amount ELSE 0 END) AS Март
FROM sales
GROUP BY manager;
Ключевые моменты:
CASEпроверяет условие и подставляет значение только для нужного месяца.SUM()илиCOUNT()агрегируют данные по группе, превращая строки в значения столбцов.GROUP BYобязателен для разбиения по измерению (например, менеджеру).
Рекомендации по применению:
- Использовать
SUM()для числовых показателей,COUNT()для подсчёта записей. - Чётко задавать список значений в
CASE, так как динамического добавления столбцов не будет. - Для сокращения кода при большом числе категорий создавать SQL-скрипт генерации запросов.
Метод гибок и работает в любой реляционной СУБД, включая MySQL, PostgreSQL и Oracle, где нет прямой поддержки PIVOT.
Решение задачи переворота таблицы в MySQL без PIVOT

В MySQL отсутствует оператор PIVOT, поэтому используется комбинация функций CASE и агрегирующих выражений. Такой подход позволяет разворачивать строки в столбцы без дополнительных расширений.
Пример: имеется таблица sales с полями month, product, amount. Необходимо вывести суммы продаж по каждому продукту в разрезе месяцев.
SELECT
month,
SUM(CASE WHEN product = 'A' THEN amount ELSE 0 END) AS product_A,
SUM(CASE WHEN product = 'B' THEN amount ELSE 0 END) AS product_B,
SUM(CASE WHEN product = 'C' THEN amount ELSE 0 END) AS product_C
FROM sales
GROUP BY month;
Каждый блок CASE формирует значение для отдельного столбца. При необходимости можно динамически строить список таких выражений с помощью скрипта на стороне приложения или хранимой процедуры, если количество уникальных значений заранее неизвестно.
При больших объемах данных рекомендуется индексировать столбцы, участвующие в фильтрации и группировке (month, product), чтобы сократить время выполнения запроса.
Таким образом, для переворота таблицы в MySQL используется комбинация CASE и GROUP BY, которая заменяет недоступный оператор PIVOT и позволяет гибко управлять структурой результата.
Пример переворота таблицы в PostgreSQL с использованием crosstab

Для демонстрации используем таблицу sales с колонками month, region и revenue:
month | region | revenue
Январь | Восток | 12000
Январь | Запад | 9000
Февраль | Восток | 15000
Февраль | Запад | 11000
Для переворота таблицы, чтобы регионы стали колонками, используем расширение tablefunc. Сначала его подключаем:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Затем формируем запрос с crosstab:
SELECT * FROM crosstab(
'SELECT month, region, revenue FROM sales ORDER BY 1,2',
'SELECT DISTINCT region FROM sales ORDER BY 1'
) AS ct(month text, Восток int, Запад int);
Результат запроса будет:
month | Восток | Запад
Январь | 12000 | 9000
Февраль | 15000 | 11000
Советы по использованию crosstab:
- Всегда упорядочивайте строки по ключевому столбцу в первом SELECT, чтобы результат был корректным.
- Колонки второго SELECT задают порядок столбцов в результирующей таблице.
- Типы данных в AS ct должны точно соответствовать содержимому столбцов.
- Для динамического набора колонок используйте функции или пишите подготовленные SQL-запросы, поскольку crosstab требует фиксированного количества колонок.
Распространённые ошибки при перевороте таблицы и способы их избежать

Переворот таблицы в SQL требует точного управления данными. Ошибки часто возникают из-за некорректной подготовки исходной таблицы или неправильного применения функций агрегирования.
- Агрегация NULL и текстовых значений: SUM, AVG и COUNT не учитывают NULL или некорректно работают с текстом.
Решение: Использовать COALESCE(столбец, 0) или CAST для приведения типов перед агрегированием. - Дублирование ключей при PIVOT: Несколько строк с одинаковым ключевым значением приводят к ошибкам или потерям данных.
Решение: Группировать по ключу заранее или применять DISTINCT на исходной таблице. - Неподготовленная структура данных: Столбец категорий должен содержать повторяющиеся значения для корректного pivot.
Решение: Создать промежуточную таблицу или CTE, нормализовав данные до pivot. - Динамические столбцы без проверки: Формирование списка столбцов через CONCAT или EXEC без фильтрации создаёт риск SQL-инъекций.
Решение: Использовать проверку допустимых значений и параметризацию. - Пропуск новых категорий: Если в исходной таблице появляются новые значения категорий, они не отобразятся в статическом PIVOT.
Решение: Применять динамический PIVOT или регулярно обновлять список столбцов в запросе. - Снижение производительности при больших таблицах: PIVOT на миллионах строк может тормозить выполнение.
Решение: Фильтровать строки по дате или другим ключам, использовать индексы на столбцах для группировки. - Несоответствие типов данных: Автоматическое преобразование типов при pivot может вызвать ошибки или потерю точности.
Решение: Явно указать тип данных через CAST или CONVERT для создаваемых столбцов.
Следование этим конкретным рекомендациям позволяет корректно выполнять переворот таблиц и предотвращает потерю данных, ошибки агрегации и снижение производительности.
Вопрос-ответ:
Что значит «перевернуть таблицу» в SQL?
Переворот таблицы в SQL обычно означает превращение строк в столбцы или наоборот. Это полезно, когда нужно представить данные в более наглядной форме, например, для отчета или сводной таблицы. Такой процесс часто реализуется с помощью конструкции PIVOT для строк в столбцы или UNPIVOT для обратного действия.
Какие функции SQL можно использовать для поворота таблицы?
Для превращения строк в столбцы в большинстве SQL-систем применяют PIVOT. Он позволяет агрегировать значения и распределять их по новым столбцам. Если требуется обратная операция, используют UNPIVOT, который превращает столбцы в строки. В некоторых случаях можно обойтись группировкой с условными выражениями, например через CASE и SUM.
Как перевернуть таблицу, если значения не числовые?
Даже если данные текстовые или даты, их можно перевернуть с помощью PIVOT или конструкции с CASE. Главное — определить столбцы, по которым будет происходить распределение строк, и выбрать агрегирующую функцию, которая поддерживает тип данных, например MAX или MIN для текста. Такой подход позволяет создать сводный вид с любыми типами значений.
Можно ли перевернуть таблицу без использования PIVOT?
Да, иногда проще обойтись без встроенного PIVOT. Для этого используют комбинацию CASE и агрегатных функций. Например, с помощью SUM(CASE WHEN…) можно распределить значения строк по новым столбцам. Этот метод работает во всех СУБД и дает полный контроль над результатом, хотя запрос может быть длиннее и требовать больше внимания к деталям.
Что делать, если количество уникальных значений в столбце заранее неизвестно?
Если число значений, которые нужно превратить в столбцы, заранее неизвестно, статический PIVOT не подходит. В таких случаях используют динамический SQL: формируется строка запроса, где список столбцов создается на основе текущих данных. После этого запрос выполняется как обычный SELECT. Это позволяет обрабатывать таблицы с любым количеством уникальных значений без ручного перечисления всех столбцов.
Как с помощью SQL превратить строки таблицы в столбцы?
В SQL для преобразования строк в столбцы можно использовать оператор PIVOT. Он позволяет сгруппировать данные по определённой колонке и создать новые столбцы на основе значений другой колонки. Например, если есть таблица с продажами по месяцам, с помощью PIVOT можно получить отдельный столбец для каждого месяца с суммой продаж. В разных СУБД синтаксис может отличаться: в Oracle и SQL Server есть встроенный PIVOT, а в MySQL и PostgreSQL приходится применять комбинацию функций агрегирования с условными выражениями, такими как CASE.
Можно ли перевернуть таблицу в SQL без использования PIVOT?
Да, это возможно при помощи агрегатных функций и конструкции CASE. Суть метода в том, чтобы явно указать условия для каждого нового столбца и сгруппировать данные по ключевым полям. Например, если таблица содержит значения продаж по продуктам и месяцам, можно написать SELECT с SUM(CASE WHEN месяц = ‘Январь’ THEN сумма ELSE 0 END) AS Январь, SUM(CASE WHEN месяц = ‘Февраль’ THEN сумма ELSE 0 END) AS Февраль и так далее. Этот способ работает в любой СУБД, даже если PIVOT отсутствует, и позволяет гибко управлять формированием итоговой таблицы.
