压制列为NULL的行

时间:2017-03-02 11:17:39

标签: postgresql

我有一个表(在PostgreSQL数据库中),其中某些id的多行有一些值,而有些则为null。 该表看起来像这样(玩具示例):

PSQL:test/me@[local]=> SELECT * FROM t1;
 id |  x  |  y  | z  
----+-----+-----+----
  1 |     | 200 |   
  1 | 100 |     | 42
  2 |  45 |     |    
(3 rows)

最重要的是:我可以保证同一个字段的行没有非NULL值的行没有行。 在上面的示例中,id 1将不会有任何其他行。

我希望聚合每个id的所有值,压缩非null值。也就是说,将它转换成类似这样的东西

 id |  x  |  y  | z  
----+-----+-----+----
  1 | 100 | 200 | 42  
  2 |  45 |     |    
(2 rows)

我最接近的是使用级联COALESCE(field1, '') || COALESCE(field2, '') || ...,但结果不是我想要的:

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)

知道如何解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

只需使用聚合,例如min() - 它将忽略空值:

select id, 
       min(x) as x, 
       min(y) as y, 
       min(z) as z
from t1
group by id;

这取决于你声称“我可以保证同一个字段中没有行,其中同一个字段具有非NULL值” - 否则这当然会返回错误的信息

或者,您可以使用array_agg()将所有值放入数组中,以防每个ID获得多个值。但string_agg()不会忽略空值,因此您需要为其应用过滤器:

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;