PostgreSQL JSON 构建一个没有空值的数组
PostgreSQL JSON building an array without null values
以下查询
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()
对我不起作用。
创建自定义函数似乎是最简单的方法。
create or replace function jsonb_build_array_without_nulls(variadic anyarray)
returns jsonb language sql immutable as $$
select jsonb_agg(elem)
from unnest() 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)
通过使用像这样的 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"}]
我假设这个查询是以某种方式动态生成的。如果您控制了 SQL 代,您也可以改用 ARRAY_AGG(...) FILTER(...)
,根据您的实际查询,这可能比使用所有不同的 更方便。
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
将空值转换为所需的字符串(唉,没有 NVL
、IFNULL
或 ISNULL
在 postgres 中,但至少 COALESCE
是可移植的)
以下查询
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()
对我不起作用。
创建自定义函数似乎是最简单的方法。
create or replace function jsonb_build_array_without_nulls(variadic anyarray)
returns jsonb language sql immutable as $$
select jsonb_agg(elem)
from unnest() 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)
通过使用像这样的 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"}]
我假设这个查询是以某种方式动态生成的。如果您控制了 SQL 代,您也可以改用 ARRAY_AGG(...) FILTER(...)
,根据您的实际查询,这可能比使用所有不同的
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
将空值转换为所需的字符串(唉,没有 NVL
、IFNULL
或 ISNULL
在 postgres 中,但至少 COALESCE
是可移植的)