2009-07-15 21 views
18

Có chức năng tương đương trục trong PostgreSQL không?unpivot và PostgreSQL

+0

Nó sẽ được tốt đẹp nếu bạn giải thích "unipivot" là những gì. –

+0

@Milen A. Radev: Trong PostgreSQL, như @Bill Karwin ghi chú bên dưới, hàm crosstab() được sử dụng cho các hoạt động trục.Tài liệu cho biết: "Chức năng crosstab được sử dụng để tạo màn hình" xoay vòng ", trong đó dữ liệu được liệt kê trên trang chứ không phải là xuống". Vì vậy, bởi unpivot, tôi giả định @Tony Searle có nghĩa là "dữ liệu được liệt kê trên trang, chứ không phải là trên." Xem câu trả lời của tôi dưới đây. – Stew

Trả lời

61

Tạo một bảng ví dụ:

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

Bạn có thể 'UNPIVOT' hoặc 'uncrosstab' sử dụng UNION ALL:

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; 

Điều này chạy 3 truy vấn phụ khác nhau trên foo, một cho e cột ach mà chúng tôi muốn bỏ khóa và trả về trong một bảng, mỗi bản ghi từ mỗi truy vấn phụ.

Nhưng điều đó sẽ quét bảng N lần, trong đó N là số cột bạn muốn bỏ ghim. Điều này là không hiệu quả, và một vấn đề lớn khi, ví dụ, bạn đang làm việc với một bảng rất lớn mà phải mất một thời gian dài để quét.

Thay vào đó, sử dụng:

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

này là dễ dàng hơn để viết, và nó sẽ chỉ quét bảng một lần.

array[a, b, c] trả về đối tượng mảng, với các giá trị a, b và c làm phần tử của nó. unnest(array[a, b, c]) ngắt kết quả thành một hàng cho mỗi phần tử của mảng.

Hy vọng điều đó sẽ hữu ích!

+1

Chiến lược 'unnest' rất hữu ích và hiệu quả trên các bảng lớn với 255 cột, cảm ơn! –

+4

Có một giải pháp khác sử dụng mô-đun 'hstore' được mô tả trong blog này: http://www.postgresonline.com/journal/archives/283-Unpivoting-data-in-PostgreSQL.html –

4

FYI cho những người trong chúng ta đang tìm cách tháo gỡ trong RedShift.

Giải pháp dạng dài được đưa ra bởi Stew dường như là cách duy nhất để thực hiện việc này.

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


Đối với những người không thể nhìn thấy nó ở đó đây là nội dung được dán bên dưới ...

Chúng tôi không có chức năng tích hợp mà sẽ làm trục hoặc UNPIVOT. Tuy nhiên, bạn luôn có thể viết SQL để làm điều đó.

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) 

truy vấn trục

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) 

truy vấn UNPIVOT

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) 

Hope this helps, Neil