开发者

Postgresql pivot? Crosstab?

I have a table (which is the result of a query) in postgres that has a set of rows (the result of a complicated summation of data) that looks like the following: (The column names are the names of each day, and the value of each column is a double precision.)

Sun   Mon   Tues   Wed   Thurs   Fri

1.24   1.11   4.51   3.21    2.21    1.01

I need to have the data selected from one row so the results look like the below:

Day   Amount

Sun   1.24

Mon   1.11

Tues  4.51

Wed   3.21

Thurs 2.21

Fri      1.01

I'm having difficulty just getting started, as I really need to cha开发者_JAVA技巧nge the column names to values and pivot the result. I tried experimenting with crosstab but I'm not entirely sure this is what I need. Any advice or suggestions that could get me going in the right direction would be very much appreciated.


Modifying @Jack Douglas's first answer:

SELECT unnest(array['sun', 'mon', 'tue', 'wed', 'thu', 'fri']) AS day,
       unnest(array[sun, mon, tue, wed, thu, fri]) AS amount
FROM t;

A little less costly according to the 9.0 query planner:

Seq Scan on t (cost=0.00..11.62 rows=360 width=192)

versus

Subquery Scan on z (cost=0.00..12.16 rows=360 width=68) -> Seq Scan on t (cost=0.00..11.26 rows=360 width=192)


test objects:

create table t ( sun numeric, 
                 mon numeric, 
                 tue numeric, 
                 wed numeric, 
                 thu numeric, 
                 fri numeric );

insert into t(sun, mon, tue, wed, thu, fri)
values(1.24, 1.11, 4.51, 3.21, 2.21, 1.01);

alternative to @Unreason's answer without a union:

select day[i], amount[i]
from ( select generate_series(1,6) as i, 
              array['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'] as day, 
              array[sun, mon, tue, wed, thu, fri] as amount
       from t ) z;

if you need to be more generic you could do something like this:

create or replace function unpivot(t) returns setof record 
                           language plpgsql immutable strict as $$
declare
  q record;
  r record;
begin
  for q in ( select attname, attnum 
             from pg_attribute 
             where attnum>0 and attrelid = ( select oid 
                                             from pg_class 
                                             where relname = 't' ) ) loop 
    for r in execute 'select '''||q.attname||'''::text, '||
                             '('||$1::text||'::t).'||q.attname||'::numeric' loop
      return next r;
    end loop;
  end loop;
  return;
end;$$;

select *
from unpivot((select row(t.*)::t from t)) 
       as foo(day text, amount numeric);

you can be a bit neater in 8.4 with a using clause in the execute but I can't test that as I am on 8.3


I don't know of direct implementation but maybe something like http://www.mail-archive.com/dhis2-users@lists.launchpad.net/msg00109.html could get you started

Of course if you don't need a flexible solution you can do

SELECT 'Sun' AS Day, Sun AS Value FROM TABLE WHERE ...
UNION ALL
SELECT 'Mon' AS Day, Mon AS Value FROM TABLE WHERE ...
UNION ALL
SELECT 'Tue' AS Day, Tue AS Value FROM TABLE WHERE ...
UNION ALL
SELECT 'Wed' AS Day, Wed AS Value FROM TABLE WHERE ...
UNION ALL
SELECT 'Thu' AS Day, Thu AS Value FROM TABLE WHERE ...
UNION ALL
SELECT 'Fri' AS Day, Fri AS Value FROM TABLE WHERE ...

(Saturday?)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜