【问题标题】:PostgreSQL JSON building an array without null valuesPostgreSQL JSON 构建一个没有空值的数组
【发布时间】:2018-07-19 22:27:08
【问题描述】:

以下查询

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() 不适合我。

【问题讨论】:

  • json_strip_nulls() 不会按设计删除所有空值,它会删除所有以空值为值的对象字段

标签: arrays json postgresql jsonb


【解决方案1】:

通过使用这样的 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) 
    

    【讨论】:

      【解决方案3】:

      我假设这个查询是动态生成的,不知何故。如果您可以控制 SQL 生成,也可以改用 ARRAY_AGG(...) FILTER(...),根据您的实际查询,这可能比使用所有不同的 array conversion functions suggested by 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
      )
      

      【讨论】:

        【解决方案4】:

        另一种处理方式如下:

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

        (不幸的是,null 本身在 postgres 或大多数其他数据库中并不能做很多事情)

        在上述情况下,'"null"' 可以替换为几乎不会被误认为数组中实时数据的任何唯一字符串。我不会使用数字,因为- 0 实际上会尝试从数组中删除第一项,而不是数组中的数字。但如果你愿意,你可以使用'"0"' 并使用- '0' 之类的东西删除。

        对于那些不使用CASE 的人,可以使用COALESCE 将空值转换为所需的字符串(唉,在postgres 中没有NVLIFNULLISNULL,但至少COALESCE 是便携)

        【讨论】:

          猜你喜欢
          • 2021-10-25
          • 1970-01-01
          • 1970-01-01
          • 2013-06-04
          • 1970-01-01
          • 1970-01-01
          • 2023-01-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多