DBAtlas · Atlas für Datenbankbetrieb

PIVOT / UNPIVOT (Zeilen↔Spalten)

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 wandelt unterschiedliche Werte in Zeilen in Spalten um (Kreuztabelle), UNPIVOT wandelt Spalten zurück in Zeilen; genutzt in Übersichts-/Berichtstabellen. Oracle bietet seit 11g eingebaute PIVOT/UNPIVOT-Operatoren; die Spaltenliste muss statisch sein (dynamische Spalten erfordern PIVOT XML oder Code).

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 hat keinen eingebauten PIVOT-Operator. Es gibt zwei Wege: die Funktion crosstab() der Extension tablefunc oder portable bedingte Aggregation (SUM(...) FILTER (WHERE ...) oder mit CASE). Die FILTER-Klausel ist eine elegante PostgreSQL-spezifische Pivot-Technik.

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 haben keinen PIVOT/UNPIVOT-Operator; eine Kreuztabelle wird manuell mit GROUP BY plus einem SUM(CASE WHEN ... THEN ... END) für jede Zielspalte gebaut. Sind die Spalten dynamisch, wird die Abfrage als String mit einem Prepared Statement erzeugt.

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 unterstützt die Operatoren PIVOT und UNPIVOT nativ seit 2005. Die PIVOT-Spaltenliste wird als statische Werte in eckigen Klammern angegeben; für dynamische Spalten wird die Abfrage mit dynamischem SQL gebaut. Für kleine Übersichten ist bedingte Aggregation (CASE) eine Alternative.

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 hat keinen PIVOT-Operator; eine Kreuztabelle wird in der Stage $group mit $sum + $cond (bedingte Aggregation) für jede Zielspalte gebaut. Für die Gegenrichtung (UNPIVOT) werden Felder mit $objectToArray und $unwind in Zeilen expandiert.

Redis

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

Redis kennt kein Konzept zum Drehen von Zeilen und Spalten. Übersichten/Kreuztabellen werden in der Anwendung berechnet; häufig angeforderte Übersichten lassen sich vorab berechnen und in Hash-Feldern speichern (ein Feld pro Spalte). RediSearch FT.AGGREGATE kann gruppiert aggregieren, ist aber kein echtes 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 hat keinen PIVOT-Operator; eine Kreuzübersicht wird mit verschachtelten terms-Aggregationen gebaut (äußerer Schlüssel / innerer Schlüssel), das Ergebnis kommt als verschachtelte Buckets statt als Spalten zurück und wird im Client in eine Tabelle umgewandelt. Ein Transform-Job kann einen gruppierten, pivot-ähnlichen Zielindex erzeugen.

In DBAtlas öffnen →