Q:

Squash rows where columns are NULL

I have a table (in a PostgreSQL DB) where multiple rows for some id have some values, while some are null.
The table looks like this (toy example):
PSQL:test/me@[local]=> SELECT * FROM t1;
 id |  x  |  y  | z  
----+-----+-----+----
  1 |     | 200 |   
  1 | 100 |     | 42
  2 |  45 |     |    
(3 rows)

Most importantly: I can guarantee that there are no rows for the same id where the same field has a non-NULL value.
In the example above, there won't be any other line for id 1.
I'm looking to aggregate all values for each id, squashing the non-null ones. That is, to transform it into something like this
 id |  x  |  y  | z  
----+-----+-----+----
  1 | 100 | 200 | 42  
  2 |  45 |     |    
(2 rows)

The closest I got was to use a cascade of COALESCE(field1, '') || COALESCE(field2, '') || ... but the result is not what I want:
PSQL:test/me@[local]=> SELECT id, COALESCE(x::TEXT || ',' , '') || COALESCE(y::TEXT || ',', '') || COALESCE(z::TEXT || ',', '') AS agg FROM t1 GROUP BY id, agg;
 id |   agg   
----+---------
  1 | 100,42,
  1 | 200,
  2 | 45,    
(3 rows)

Any idea how to solve this problem?

A:

Just use an aggregate, e.g. min()- it will ignore the null values:
select id, 
       min(x) as x, 
       min(y) as y, 
       min(z) as z
from t1
group by id;

This relies on your claim that "I can guarantee that there are no rows for the same id where the same field has a non-NULL value" - otherwise this would of course return the wrong information.

Alternatively you could use array_agg() to put all values into an array just in case you might get multiple values per id.  But string_agg() doesn't ignore null values so you need to apply a filter for that:
select id, 
       array_agg(x) filter (where x is not null), 
       array_agg(y) filter (where y is not null),
       array_agg(z) filter (where z is not null)
from t1
group by id;

