Postgresql LEFT JOIN json_agg()忽略/删除NULL

use*_*211 43 sql postgresql json postgresql-9.3

SELECT C.id, C.name, json_agg(E) AS emails FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id;
Run Code Online (Sandbox Code Playgroud)

例如,Postgres 9.3创建输出

  id  |  name  |  emails
-----------------------------------------------------------
   1  |  Ryan  |  [{"id":3,"user_id":1,"email":"hello@world.com"},{"id":4,"user_id":1,"email":"again@awesome.com"}]
   2  |  Nick  |  [null]
Run Code Online (Sandbox Code Playgroud)

由于我使用LEFT JOIN,因此会出现没有右表匹配的情况,因此将空(null)值替换为右表列.因此,我将[null]作为JSON聚合之一获得.

我如何忽略/删除null所以[]当右表列为空时我有一个空的JSON数组?

干杯!

小智 64

在9.4中,您可以使用coalesce和聚合过滤器表达式.

SELECT C.id, C.name, 
  COALESCE(json_agg(E) FILTER (WHERE E.user_id IS NOT NULL), '[]') AS emails 
FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id, C.name
ORDER BY C.id;
Run Code Online (Sandbox Code Playgroud)

过滤器表达式可防止聚合处理空行,因为不满足左连接条件,因此最终使用数据库null而不是json [null].一旦数据库为null,就可以像往常一样使用coalesce.

http://www.postgresql.org/docs/9.4/static/sql-expressions.html#SYNTAX-AGGREGATES

  • 这很棒!它也适用于`json_object_agg`:`COALESCE(json_object_agg(prop.key,prop.value)FILTER(WHERE prop.key IS NOT NULL),'{}'):: json` (3认同)
  • 8 年后,Postgresql 12.x 完美解决了我的问题。 (3认同)

Rom*_*kar 14

这样的事情可能会是什么?

select
    c.id, c.name,
    case when count(e) = 0 then '[]' else json_agg(e) end as emails
from contacts as c
    left outer join emails as e on c.id = e.user_id
group by c.id
Run Code Online (Sandbox Code Playgroud)

sql fiddle demo

你也可以在加入之前进行分组(我更喜欢这个版本,它更清楚一点):

select
    c.id, c.name,
    coalesce(e.emails, '[]') as emails
from contacts as c
    left outer join (
        select e.user_id, json_agg(e) as emails from emails as e group by e.user_id
    ) as e on e.user_id = c.id
Run Code Online (Sandbox Code Playgroud)

sql fiddle demo


Jef*_*eff 6

如果这实际上是一个 PostgreSQL 错误,我希望它已在 9.4 中修复。很烦人。

SELECT C.id, C.name, 
  COALESCE(NULLIF(json_agg(E)::TEXT, '[null]'), '[]')::JSON AS emails 
FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id;
Run Code Online (Sandbox Code Playgroud)

我个人不做 COALESCE 位,只返回 NULL。您的来电。


Fab*_*tor 0

这种方法可行,但必须有更好的方法:(

SELECT C.id, C.name, 
  case when exists (select true from emails where user_id=C.id) then json_agg(E) else '[]' end
FROM contacts C
LEFT JOIN emails E ON C.id = E.user_id
GROUP BY C.id, C.name;
Run Code Online (Sandbox Code Playgroud)

演示: http: //sqlfiddle.com/#!15/ddefb /16