2009-07-15 8 views
18

Gibt es in PostgreSQL eine Unpivot-äquivalente Funktion?Unpivot und PostgreSQL

+0

Es wäre schön, wenn Sie erklären, was "UniPivot". –

+0

@Milen A. Radev: In PostgreSQL, wie @ Bill Karwin unten bemerkt, wird die Kreuztabellenfunktion für Pivot-Operationen verwendet.Das Dokument sagt: "Die Kreuztabellenfunktion wird verwendet, um" Pivot "-Anzeigen zu erstellen, bei denen Daten über die Seite statt nach unten aufgelistet werden." Ich nehme an, dass @Tony Searle bedeutet, dass die Daten auf der Seite aufgelistet sind und nicht auf der anderen Seite. Siehe meine Antwort unten. – Stew

Antwort

61

ein Beispiel Tabelle erstellen:

CREATE TEMP TABLE foo (id int, a text, b text, c text); 
INSERT INTO foo VALUES (1, 'ant', 'cat', 'chimp'), (2, 'grape', 'mint', 'basil'); 

Sie können 'Entpivotisierung' oder 'uncrosstab' ALL UNION mit:

SELECT id, 
     'a' AS colname, 
     a AS thing 
FROM foo 
UNION ALL 
SELECT id, 
     'b' AS colname, 
     b AS thing 
FROM foo 
UNION ALL 
SELECT id, 
     'c' AS colname, 
     c AS thing 
FROM foo 
ORDER BY id; 

Dies führt 3 verschiedene Unterabfragen auf foo, eine für e Ach Spalte, die wir deaktivieren möchten, und gibt in einer Tabelle jeden Datensatz aus jeder der Unterabfragen zurück.

Aber das wird die Tabelle N Mal scannen, wobei N die Anzahl der Spalten ist, die Sie deaktivieren möchten. Dies ist ineffizient und ein großes Problem, wenn Sie zum Beispiel mit einer sehr großen Tabelle arbeiten, die viel Zeit zum Scannen benötigt.

Verwenden Sie stattdessen:

SELECT id, 
     unnest(array['a', 'b', 'c']) AS colname, 
     unnest(array[a, b, c]) AS thing 
FROM foo 
ORDER BY id; 

Dies ist einfacher zu schreiben, und es wird die Tabelle nur einmal scannen.

array[a, b, c] gibt ein Array-Objekt mit den Werten von a, b und c als Elemente zurück. unnest(array[a, b, c]) bricht die Ergebnisse für jedes Element des Arrays in eine Zeile auf.

Hoffe, dass hilft!

+1

Die 'unnest'-Strategie ist sehr nützlich und effizient auf großen Tabellen mit 255 Spalten, danke! –

+4

Es gibt eine andere Lösung, die das 'hstore' Modul verwendet, das in diesem Blog beschrieben wird: http://www.postgresonline.com/journal/archives/283-Unpivoting-data-in-PostgreSQL.html –

4

FYI für diejenigen von uns suchen, wie in RedShift zu entmutigen.

Die Langformlösung, die von Stew gegeben wird, scheint der einzige Weg zu sein, dies zu erreichen.

https://forums.aws.amazon.com/thread.jspa?threadID=126369


Für diejenigen, die es nicht gibt hier sehen kann, ist der Text eingefügt ...

Wir haben keine integrierten Funktionen haben, die Schwenk- oder Entpivotisierung tun. Aber Sie können immer SQL schreiben, um das zu tun.

create table sales (regionid integer, q1 integer, q2 integer, q3 integer, q4 integer); 
insert into sales values (1,10,12,14,16), (2,20,22,24,26); 

select * from sales order by regionid; 

regionid | q1 | q2 | q3 | q4 
----------+----+----+----+---- 
1 | 10 | 12 | 14 | 16 
2 | 20 | 22 | 24 | 26 

(2 rows) 

Pivot-Abfrage

create table sales_pivoted (regionid, quarter, sales) 
as 
select regionid, 'Q1', q1 from sales 
UNION ALL 
select regionid, 'Q2', q2 from sales 
UNION ALL 
select regionid, 'Q3', q3 from sales 
UNION ALL 
select regionid, 'Q4', q4 from sales 
; 

select * from sales_pivoted order by regionid, quarter; 

regionid | quarter | sales 
----------+---------+------- 
1 | Q1 | 10 
1 | Q2 | 12 
1 | Q3 | 14 
1 | Q4 | 16 
2 | Q1 | 20 
2 | Q2 | 22 
2 | Q3 | 24 
2 | Q4 | 26 
(8 rows) 

Entpivotisierung Abfrage

select regionid, sum(Q1) as Q1, sum(Q2) as Q2, sum(Q3) as Q3, sum(Q4) as Q4 
from 
(select regionid, 
case quarter when 'Q1' then sales else 0 end as Q1, 
case quarter when 'Q2' then sales else 0 end as Q2, 
case quarter when 'Q3' then sales else 0 end as Q3, 
case quarter when 'Q4' then sales else 0 end as Q4 
from sales_pivoted) 

group by regionid 
order by regionid; 
regionid | q1 | q2 | q3 | q4 
----------+----+----+----+---- 
1 | 10 | 12 | 14 | 16 
2 | 20 | 22 | 24 | 26 
(2 rows) 

hoffe, das hilft, Neil