Question

I'm trying to pivot a table in Postgres. My table 'sample' has many columns (code, sector, item, year, period, value, preorder), instead of having 1 concept, 1 year, 1 value per row, i want the concept with values by year. From this;

Item            Value   Year    PreOrder
Sales             50    2011    1
Costs            -20    2011    2
GrossProfit       30    2011    3
Expenses          -5    2011    4
Tax               -3    2011    5
Profit            22    2011    6
Sales             45    2012    3
Costs            -20    2012    4
GrossProfit       25    2012    5
Expenses          -5    2012    6
Tax               -3    2012    7
Profit            17    2012    8

To this:

Item        2011    2012
Sales         50    45
Costs        -20    -20
GrossProfit   30    25
Expenses      -5    -5
Tax           -3    -3
Profit        22    17

Using crosstab in Postgres:

Select * from crosstab($$Select item, year, value from sec_sample
    Where cik=320193
    AND period='Annual'
    AND Sector='Agro'
    Order by year, preorder
    $$,
    $$VALUES ('2011'::int), ('2012')$$)
AS value("item" varchar(255), "2011" numeric(20,2), "2012" numeric(20,2));

However this results in:

Item        2011    2012
Sales         50    
Costs        -20    
GrossProfit   30    
Expenses      -5    
Tax           -3    
Profit        22    
Sales               45
Costs              -20
GrossProfit         25
Expenses            -5
Tax                 -3
Profit              17

Any idea how i can modify my query? Thx

Was it helpful?

Solution

AFAIK, to group by item you have to order by item:

Select * from crosstab($$Select item, year, value from sec_sample
    Where cik=320193
    AND period='Annual'
    AND Sector='Agro'
    Order by item, year, preorder
    $$,
    $$VALUES ('2011'::int), ('2012')$$)
AS value("item" varchar(255), "2011" numeric(20,2), "2012" numeric(20,2));

But you can pivot without using crosstab, like this:

select
    s.item,
    sum(case when s.year = 2011 then s.value else 0 end) as "2011",
    sum(case when s.year = 2012 then s.value else 0 end) as "2012"
from sec_sample as s
group by s.item
order by min(s.preorder)

I think it's easier to modify this type of query

sql fiddle demo

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top