【问题标题】:PostgreSQL: select from field with json formatPostgreSQL:从 json 格式的字段中选择
【发布时间】:2021-12-11 14:12:51
【问题描述】:

表有列,名为“config”,内容如下:

   {
     "A":{
        "B":[
              {"name":"someName","version":"someVersion"},
              {"name":"someName","version":"someVersion"}
            ]
         }
    }

任务是选择所有名称和版本值。输出预期选择 2 列:名称和值。

我成功选择了B的内容:

select config::json -> 'A' -> 'B' as B
from my_table;

但是当我尝试做类似的事情时:

select config::json -> 'A' -> 'B' ->> 'name' as name,
       config::json -> 'A' -> 'B' ->> 'version' as version
from my_table;

我收到带有空值列的选择

【问题讨论】:

  • 为什么要使用::json 演员表?如果该列存储 JSON 数据,则应将其定义为 jsonb 或至少 json

标签: sql json postgresql


【解决方案1】:

如果数组大小是固定的,你只需要告诉你要检索数组的哪个元素,例如:

SELECT config->'A'->'B'->0->>'name' AS name,
       config->'A'->'B'->0->>'version' AS version
FROM my_table;

但由于您的数组包含多个元素,请在子查询或 CTE 中使用函数 jsonb_array_elements,并在外部查询中单独解析每个元素,例如:

SELECT rec->>'name', rec->>'version'
FROM (SELECT jsonb_array_elements(config->'A'->'B') 
      FROM my_table) j (rec);

演示:db<>fiddle

【讨论】:

    【解决方案2】:

    首先你应该使用 jsonb 数据类型而不是 json,参见documentation

    一般来说,大多数应用程序应该更喜欢将 JSON 数据存储为 jsonb,除非有非常特殊的需求,例如遗留 关于对象键排序的假设。

    使用 jsonb,您可以执行以下操作:

    SELECT DISTINCT ON (c) c->'name' AS name, c->'version' AS version
    FROM my_table
    CROSS JOIN LATERAL jsonb_path_query(config :: jsonb, '$.** ? (exists(@.name))') AS c
    

    【讨论】:

      【解决方案3】:

      dbfiddle

      select e.value ->> 'name', e.value ->> 'version'
      from 
        my_table cross join json_array_elements(config::json -> 'A' -> 'B') e
      

      【讨论】:

        猜你喜欢
        • 2012-05-04
        • 2017-05-04
        • 2012-12-19
        • 1970-01-01
        • 1970-01-01
        • 2020-08-17
        • 2023-01-18
        • 2013-08-13
        • 2019-10-16
        相关资源
        最近更新 更多