2

Here is an example table called animal:

name | color
------------
fox  | brown
fox  | red
dog  | gold

Now, what I want is this result:

fox   | dog
-------------
brown | gold
red   | 

The names should be columns of the result with the different color values as rows.

My first thought was like:

SELECT color
FROM animal
WHERE name='fox'

[some sort of join?]

SELECT color 
FROM animal
WHERE name='dog'

But I don't know what kind of join would do the trick.

Second thought:

SELECT CASE WHEN name = 'fox' THEN color ELSE NULL END AS fox,
CASE WHEN name = 'dog' THEN color ELSE NULL END AS dog
FROM animal

This returns:

fox   | dog
-----------
red   | 
brown |
      | gold

I would like to move the null values in this table to the end. I tried to:

ORDER BY CASE name
        WHEN 'fox' THEN fox
        WHEN 'dog' THEN dog
    END

But I'm not sure if this is really what I want and Postgres is nagging that fox is not a column although I can do ORDER BY fox.

Maybe my approach is total nonsense or there is some kind of coalesce magic that can do the trick?

Jasen
  • 11,837
  • 2
  • 30
  • 48
mihca
  • 997
  • 1
  • 10
  • 29

2 Answers2

3

You seem to be under the impression that there would be a "natural" order in a table (like in a spreadsheet), but there is not. Without ORDER BY, rows are returned in arbitrary order - which often happens to be identical to input order for small tables that have not been updated, yet.

WITH cte AS (
   SELECT row_number() OVER (PARTITION BY name ORDER BY color) AS rn, * 
   FROM   animal
   )
SELECT f.color AS fox, d.color AS dog
FROM        (SELECT rn, color FROM cte WHERE name = 'fox') f
FULL   JOIN (SELECT rn, color FROM cte WHERE name = 'dog') d USING (rn)
ORDER  BY rn;

Major points

Attach sequential numbers per color for each type of animal separately in a CTE.

The FULL [OUTER] JOIN is crucial, since the number of rows for 'fox' and 'dog' differ.

Colors are sorted alphabetically, NULL values are last automatically in default ASCENDING sort order. See:

This only scans the table once.

Explanation for the error message you got ("fox" is not a column):

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
1

Try something like:

WITH fox_color as 
(SELECT color as fox, row_number() rn
 FROM animal
 WHERE name='fox'),
dog_color as 
(SELECT color as dog, row_number() rn
 FROM animal
 WHERE name='dog')
SELECT fox, dog
FROM fox_color 
JOIN dog_color ON fox_color.rn = dog_color.rn
Ihor Romanchenko
  • 26,995
  • 8
  • 48
  • 44