PostgreSQL JSON 构建不带空值的数组

问题描述 投票:0回答:5

以下查询

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()
对我不起作用。

arrays json postgresql jsonb
5个回答
3
投票

通过使用这样的 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"}]

2
投票

创建自定义函数似乎是最简单的方法。

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) 

2
投票

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)

1
投票

我假设这个查询是动态生成的,不知何故。如果您可以控制 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
)

1
投票

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

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
是可移植的)

© www.soinside.com 2019 - 2024. All rights reserved.