DBAtlas · Атлас эксплуатации баз данных

PIVOT / UNPIVOT (строки↔столбцы)

Oracle

-- Turn sales by month into columns
SELECT * FROM (
  SELECT month, amount FROM sale
)
PIVOT (SUM(amount) FOR month IN ('Jan' AS jan, 'Feb' AS feb, 'Mar' AS mar));

-- UNPIVOT: turn columns back into rows
SELECT product, month, amount
FROM sale_wide
UNPIVOT (amount FOR month IN (jan AS 'Jan', feb AS 'Feb'));

PIVOT превращает различные значения в строках в столбцы (перекрёстная таблица), а UNPIVOT — столбцы обратно в строки; используется в сводных/отчётных таблицах. Oracle предлагает встроенные операторы PIVOT/UNPIVOT с 11g; список столбцов должен быть статическим (динамические столбцы требуют PIVOT XML или кода).

PostgreSQL

-- The tablefunc extension for crosstab
CREATE EXTENSION IF NOT EXISTS tablefunc;
SELECT * FROM crosstab(
  'SELECT product, month, amount FROM sale ORDER BY 1,2'
) AS ct(product text, jan numeric, feb numeric, mar numeric);

-- Without an extension: conditional aggregation
SELECT product,
  SUM(amount) FILTER (WHERE month = 'Jan') AS jan,
  SUM(amount) FILTER (WHERE month = 'Feb') AS feb
FROM sale GROUP BY product;

В PostgreSQL нет встроенного оператора PIVOT. Есть два способа: функция crosstab() расширения tablefunc или переносимая условная агрегация (SUM(...) FILTER (WHERE ...) или с CASE). Предложение FILTER — элегантная техника pivot, специфичная для PostgreSQL.

MySQL

-- There is no PIVOT; conditional aggregation with manual CASE
SELECT product,
  SUM(CASE WHEN month = 'Jan' THEN amount ELSE 0 END) AS jan,
  SUM(CASE WHEN month = 'Feb' THEN amount ELSE 0 END) AS feb,
  SUM(CASE WHEN month = 'Mar' THEN amount ELSE 0 END) AS mar
FROM sale
GROUP BY product;

В MySQL/MariaDB нет операторов PIVOT/UNPIVOT; перекрёстная таблица строится вручную через GROUP BY плюс SUM(CASE WHEN ... THEN ... END) для каждого целевого столбца. Если столбцы динамические, запрос генерируется строкой через prepared statement.

SQL Server

SELECT * FROM (
  SELECT product, month, amount FROM sale
) src
PIVOT (
  SUM(amount) FOR month IN ([Jan], [Feb], [Mar])
) pvt;

-- Converting back with UNPIVOT is also supported

SQL Server нативно поддерживает операторы PIVOT и UNPIVOT с 2005. Список столбцов PIVOT задаётся статическими значениями в квадратных скобках; для динамических столбцов запрос строится динамическим SQL. Для небольших сводок альтернатива — условная агрегация (CASE).

MongoDB

// PIVOT equivalent: conditional aggregation inside $group
db.sale.aggregate([
  { $group: {
      _id: "$product",
      jan: { $sum: { $cond: [ { $eq: ["$month", "Jan"] }, "$amount", 0 ] } },
      feb: { $sum: { $cond: [ { $eq: ["$month", "Feb"] }, "$amount", 0 ] } }
  } }
])

В MongoDB нет оператора PIVOT; перекрёстная таблица строится на этапе $group через $sum + $cond (условная агрегация) для каждого целевого столбца. В обратном направлении (UNPIVOT) поля разворачиваются в строки через $objectToArray и $unwind.

Redis

# Not applicable: Redis has no pivot/cross tab.

В Redis нет понятия поворота строк и столбцов. Сводки/перекрёстные таблицы вычисляются на стороне приложения; часто запрашиваемые сводки можно предвычислить и хранить в полях Hash (одно поле на столбец). RediSearch FT.AGGREGATE умеет групповую агрегацию, но это не настоящий pivot.

Elasticsearch

# Closest equivalent: nested terms aggregations
GET sale/_search
{
  "size": 0,
  "aggs": { "product": { "terms": { "field": "product" },
    "aggs": { "month": { "terms": { "field": "month" },
      "aggs": { "total": { "sum": { "field": "amount" } } } } } }
}

В Elasticsearch нет оператора PIVOT; перекрёстная сводка строится вложенными агрегациями terms (внешний ключ / внутренний ключ), результат возвращается вложенными бакетами, а не столбцами, и превращается в таблицу на клиенте. Задание transform может создать сгруппированный целевой индекс, похожий на pivot.

Открыть в DBAtlas →