以下查询
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)
Postgres 16 确实引入了 JSON 构造函数,例如
json_array
。
如果指定了
,则忽略ABSENT ON NULL
值NULL
所以你可以使用
SELECT json_array(
json_object('use': 'Home'),
(CASE WHEN 1 = 2 THEN json_object('use': 'Work') END),
ABSENT ON NULL
)
对于 JSONB,没有
jsonb_array
函数,而是使用
json_array(… ABSENT ON NULL RETURNING jsonb)
我假设这个查询是动态生成的,不知何故。如果您可以控制 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 或大多数其他数据库中,单独使用
null
并不能做太多事情)
在上面的情况下,
'"null"'
可以替换为任何不会被误认为数组中的实时数据的唯一字符串。我不会使用数字,因为 - 0
实际上会尝试从数组中删除第一项,而不是数组中的数字。但如果您愿意,您可以使用 '"0"'
并使用 - '0'
之类的内容删除。
对于那些不使用
CASE
的人,可以使用 COALESCE
将空值转换为所需的字符串(唉,postgres 中没有 NVL
、IFNULL
或 ISNULL
,但至少 COALESCE
是可移植的)