Conditions: PostgreSQL 8.4 (this would be too simple with 9.x)
Table:
id | gpa | class | rank
----+-----+---------+--------
1 | 2.0 | english | low
1 | 2.0 | math | low
1 | 2.0 | pe | low
1 | 2.0 | spanish | medium
2 | 3.5 | english | high
2 | 3.5 | history | high
2 | 3.5 | art | great
2 | 3.5 | tech | high
3 | 4.0 | pe | medium
3 | 4.0 | spanish | high
3 | 4.0 | english | great
3 | 4.0 | art | great
Wanted:
id | gpa | great | high | medium | low
----+-----+--------------+------------------------+---------+-----
1 | 2.0 | | | spanish | english, math, pe
2 | 3.5 | art | english, history, tech | |
3 | 4.0 | art, english | spanish | pe |
Current Method:
WITH details AS (
select * from table order by rank, class
)
SELECT id
, gpa
, array_to_string(array_agg(CASE WHEN rank='great' THEN class END,', ')) as great
, array_to_string(array_agg(CASE WHEN rank='high' THEN class END,', ')) as high
, array_to_string(array_agg(CASE WHEN rank='medium' THEN class END,', ')) as medium
, array_to_string(array_agg(CASE WHEN rank='low' THEN class END,', ')) as low
FROM details
ORDER BY gpa;
So I tried to put this as an example from what I'm doing - no I don't have an actual table with this structure that isn't much normalized, but I do have a subquery that produces something like this.
In actuality my array_agg() is also concatenating two fields (a word and a number) and i'm sorting by the number e.g.(array_agg(CASE ... THEN foo || ' - ' || bar), unfortunately my output is only mostly sorted. Perhaps I can improve this question if I have more time.