2017-03-02 39 views
0

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

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

更重要的是:我可以保证,有对同一编号行,其中同一领域具有非NULL值。 在上面的例子中,不会有任何其他行ID为1.

我期待聚合每个id的所有值,挤压非空的。也就是说,将其改造成这样的

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

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

PSQL:test/[email protected][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) 

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

回答

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获得多个值。

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; 
+0

感谢提供无论是“分”的解决方案,它依赖于我的要求,也是通用的解决方案:但是string_agg()所以你需要应用一个过滤器不忽略空值。这两个奇迹! – Jir