Что есть в стандарте sql ^^ pivot or transpose or convert
Разберу вопрос подробно — с акцентом на стандарты SQL и практические реализации.В официальном стандарте SQL (ANSI/ISO) нет операторов PIVOT, TRANSPOSE или CONVERT для преобразования структуры таблиц. Эти операции решаются разными способами в зависимости от СУБД.
- базовые операции SELECT, JOIN, GROUP BY;
- агрегатные функции (SUM, AVG, COUNT и т. д.);
- оконные функции (с SQL:2003);
- общие табличные выражения (CTE, с SQL:1999).
Эти инструменты позволяют эмулировать PIVOT и TRANSPOSE.
PIVOT (свод/поворот данных)
Преобразует строки в столбцы на основе группировки и агрегации.
Синтаксис (SQL Server, Oracle):
SELECT *
FROM source_table
PIVOT (
агрегатная_функция(столбец_для_агрегации)
FOR столбец_для_поворота IN (значения)
) AS pivot_table;Пример (SQL Server):
-- Исходные данные: category, year, sales
SELECT *
FROM sales
PIVOT (
SUM(sales)
FOR year IN ([2020], [2021], [2022])
) AS pvt;Эмуляция в PostgreSQL/MySQL (через CASE):
SELECT
category,
SUM(CASE WHEN year = 2020 THEN sales ELSE 0 END) AS "2020",
SUM(CASE WHEN year = 2021 THEN sales ELSE 0 END) AS "2021",
SUM(CASE WHEN year = 2022 THEN sales ELSE 0 END) AS "2022"
FROM sales
GROUP BY category;TRANSPOSE (транспонирование)
Меняет местами строки и столбцы (аналог транспонирования матрицы). В SQL нет встроенной поддержки — реализуется через:
- UNION ALL (универсально):
SELECT 'sales_2020' AS metric, A_2020 AS A, B_2020 AS B FROM dual
UNION ALL
SELECT 'sales_2021' AS metric, A_2021 AS A, B_2021 AS B FROM dual;- CROSS JOIN + условная агрегация (для динамических сценариев):
WITH years AS (SELECT DISTINCT year FROM sales),
categories AS (SELECT DISTINCT category FROM sales)
SELECT y.year AS row_label,
MAX(CASE WHEN c.category = 'A' THEN s.sales END) AS A,
MAX(CASE WHEN c.category = 'B' THEN s.sales END) AS B
FROM years y
CROSS JOIN categories c
LEFT JOIN sales s ON y.year = s.year AND c.category = s.category
GROUP BY y.year;- Рекурсивные CTE (для сложных иерархий).
CONVERT (преобразование типов)
Отличается от PIVOT/TRANSPOSE: меняет тип данных столбца, а не структуру таблицы.
Стандартные функции:
- CAST(выражение AS тип) — ANSI‑совместимо;
- CONVERT(тип, выражение) — специфично для SQL Server.
Примеры:
-- ANSI SQL (работает везде)
SELECT CAST(price AS DECIMAL(10,2)) FROM products;
-- SQL Server
SELECT CONVERT(DECIMAL(10,2), price) FROM products;
-- Преобразование даты
SELECT CAST('2023-01-01' AS DATE);Сравнение подходов
| Операция | Назначение | Стандарт SQL | Поддержка СУБД | Пример использования |
|---|---|---|---|---|
| PIVOT | Строки → столбцы (агрегация) | Нет | SQL Server, Oracle (частично) | Сводные отчёты по годам |
| TRANSPOSE | Поменять строки/столбцы местами | Нет | Нет встроенной поддержки | Анализ матриц, кросс‑таблицы |
| CAST/CONVERT | Преобразование типов данных | CAST — да, CONVERT — нет | Везде (CAST), SQL Server (CONVERT) | Приведение типов, форматирование дат |
Практические рекомендации
Для PIVOT:
- используйте встроенный PIVOT, если СУБД поддерживает (SQL Server, Oracle);
- для PostgreSQL/MySQL применяйте CASE + GROUP BY или оконные функции;
- динамический PIVOT реализуйте через генерацию SQL‑кода в приложении.
Для TRANSPOSE:
- выбирайте UNION ALL, если число столбцов фиксировано;
- используйте CROSS JOIN, если структура динамическая;
- рассмотрите обработку на уровне приложения (Python/Pandas, Excel).
Для CONVERT:
- отдавайте предпочтение CAST для переносимости;
- используйте CONVERT, если нужны специфические форматы (например, даты в SQL Server).
Примеры для разных СУБД
PostgreSQL (PIVOT через crosstab):
CREATE EXTENSION IF NOT EXISTS tablefunc;
SELECT * FROM crosstab(
'SELECT category, year, SUM(sales) FROM sales GROUP BY 1,2 ORDER BY 1,2',
'SELECT DISTINCT year FROM sales ORDER BY 1'
) AS ct(category TEXT, "2020" INT, "2021" INT, "2022" INT);MySQL (динамический PIVOT через хранимую процедуру):
SET @sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT('SUM(IF(year = ', year, ', sales, 0)) AS `', year, '`')
) INTO @sql
FROM sales;
SET @sql = CONCAT('SELECT category, ', @sql, ' FROM sales GROUP BY category');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;Если хотите, могу привести более детальные примеры для вашей конкретной СУБД или сценария — уточните задачу!










