PostgreSQL JSON构建了一个没有null值的数组



以下查询

SELECT jsonb_build_array(jsonb_build_object('use', 'Home'), 
CASE WHEN 1 = 2 THEN jsonb_build_object('use', 'Work')
END)

产生

[{"use":"Home"},null]

当我真正想要时

[{"use":"Home"}]

我该怎么做?json_strip_nulls()对我不起作用。

通过使用这样的PostgreSQL数组:

SELECT array_to_json(array_remove(ARRAY[jsonb_build_object('use', 'Home'), 
CASE WHEN 1 = 2 THEN jsonb_build_object('use', 'Work') END], null))

它确实产生:

[{"use": "Home"}]

当然:

SELECT array_to_json(array_remove(ARRAY[jsonb_build_object('use', 'Home'), 
CASE WHEN 1 = 2 THEN jsonb_build_object('use', 'Work') END,
jsonb_build_object('real_use', 'NotHome')], null))

确实产生:

[{"use": "Home"},{"real_use": "NotHome"}]
创建自定义函数似乎是最简单的方法。
create or replace function jsonb_build_array_without_nulls(variadic anyarray)
returns jsonb language sql immutable as $$
select jsonb_agg(elem)
from unnest($1) as elem
where elem is not null
$$;
select 
jsonb_build_array_without_nulls(
jsonb_build_object('use', 'home'), 
case when 1 = 2 then jsonb_build_object('use', 'work') end
)
jsonb_build_array_without_nulls 
---------------------------------
[{"use": "home"}]
(1 row) 

我假设这个查询是动态生成的。如果您控制SQL生成,也可以使用ARRAY_AGG(...) FILTER(...),根据您的实际查询,它可能比使用Patrick建议的所有不同的数组转换函数更方便。

SELECT (
SELECT json_agg(v) FILTER (WHERE v IS NOT NULL)
FROM (
VALUES 
(jsonb_build_object('use', 'Home')),
(CASE WHEN 1 = 2 THEN jsonb_build_object('use', 'Work') END)
) t (v)
)

或者:

SELECT (
SELECT json_agg(v)
FROM (
VALUES 
(jsonb_build_object('use', 'Home')),
(CASE WHEN 1 = 2 THEN jsonb_build_object('use', 'Work') END)
) t (v)
WHERE v IS NOT NULL
)

处理此问题的另一种方法如下:

SELECT jsonb_build_array(
jsonb_build_object('use', 'Home'), 
CASE 
WHEN 1 = 2 THEN jsonb_build_object('use', 'Work')
ELSE '"null"'
END
) - 'null'

(不幸的是,在postgres或大多数其他DB中,null本身实际上不可能做太多事情(

在上面的例子中,'"null"'可以被替换为几乎任何唯一的字符串,这些字符串不会被误认为是数组中的活动数据。我不会使用数字,因为- 0实际上会尝试从数组中删除第一个项目,而不是数组中的数字。但是,如果您愿意的话,您可能可以使用'"0"'并使用类似- '0'的东西来移除。

对于那些不使用CASE的人,可以使用COALESCE将null转换为所需的字符串(唉,postgres中没有NVLIFNULLISNULL,但至少COALESCE是可移植的(

最新更新