RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1607846
Accepted
Angelina
Angelina
Asked:2025-02-28 05:28:23 +0000 UTC2025-02-28 05:28:23 +0000 UTC 2025-02-28 05:28:23 +0000 UTC

如何将具有不同结构的 JSON 字符串正确解析为一列(PostgreSQL)?

  • 772

有一个表,其中 pars_col 列包含不同结构的 json 字符串。第一行类型:{'values': [{'test': 'A', 'values': [{'value': 8, 'test': 'B'}]}]},第二行类型:{'values': [{'value': 21.0, 'test': 'D'}]}。一行可以包含多个在测试中含义不同、名称不同的值。我需要提取每一行的所有值并将它们相加。所有这些都需要保存在一列中。

代码有几个错误,感谢@ValNik,他的评论使它变得更好。还剩下一个问题,我的代码没有从数组双重嵌套的行中提取所有值。

例如表格中包含一行:{"values": [{"test": "A", "values": [{"value": 2, "test": "B"}]}, {"test": "D", "values": [{"value": 3, "test": "E"}]}]}'::TEXT),代码只会从中提取2,但是需要提取2和3并将它们相加。

我的代码:

-- временная таблица для примера 
CREATE TEMP VIEW df AS
SELECT
    prg_id,
    name,
    dt,
    pars_col::json as pars_col
FROM
(
    SELECT
        prg_id,
        name,
        dt,
        pars_col
    FROM
        (VALUES
            (1, 'Product A', '2023-01-01'::DATE, '{"values": [{"test": "A", "values": [{"value": 8, "test": "B"}]}]}'::TEXT),
            (2, 'Product B', '2023-02-01'::DATE, '{"values": [{"value": 21.0, "test": "D"}]}'::TEXT),
            (23, 'Product C', '2023-01-01'::DATE, '{"values": [{"test": "A", "values": [{"value": 5, "test": "B"}]}, {"value": 10, "test": "D"}]}'::TEXT),
            (245, 'Product D', '2023-02-01'::DATE, '{"values": [{"test": "A", "values": [{"value": 2, "test": "B"}]}, {"test": "D", "values": [{"value": 3, "test": "E"}]}]}'::TEXT),
            (32, 'Product E', '2023-01-01'::DATE, '{"values": [{"value": 15, "test": "F"}]}'::TEXT),
            (31, 'Product G', '2023-02-01'::DATE, '{"values": [{"test": "G", "values": [{"value": 7, "test": "H"}]}]}'::TEXT)
        ) AS data(prg_id, name, dt, pars_col)
) as sub; 

-- запрос, с помощью которого я пытаюсь распарсить строки в колонке pars_col
SELECT
    prg_id,
    name,
    dt,
    sum(combined.value)
FROM df 
    CROSS JOIN LATERAL (
        SELECT
            SUM((elem ->> 'value')::numeric) AS value
        FROM
            pg_catalog.json_array_elements(pars_col -> 'values') AS elem

        UNION 

        SELECT
            SUM((elem2 ->> 'value')::numeric) AS value
        FROM
            pg_catalog.json_array_elements((pars_col -> 'values') -> 0 -> 'values') AS elem2
    ) AS combined
GROUP BY prg_id, name, dt

输出为: 查询结果

该表显示 prg_id 245 未完全提取值。请帮我修复错误。

sql
  • 1 1 个回答
  • 63 Views

1 个回答

  • Voted
  1. Best Answer
    ValNik
    2025-03-03T06:49:11Z2025-03-03T06:49:11Z

    由于您没有定义数组嵌套,因此需要使用递归查询将其分解为元素。
    例如,对于 prg_id=402,嵌套级别为 3,递归级别为 0,1,2。
    如果数组是数组,我们会在每一步中将其(elem)拆分为元素。如果 elem 不是数组,则递归停止。
    字符串是否是最终元素 - 检查

    where elem::jsonb ? 'value'
    

    然后我们只取这些元素。
    接下来我们从 elem 中提取值cast(elem ->>'value' as numeric)并求和。

    看一下例子。

    prg_id 姓名 日期 pars_col
    1 产品 A 2023-01-01 {“值”:[{“测试”:“A”,“值”:[{“值”:8,“测试”:“B”}]}]}
    2 产品 B 2023-02-01 {“值”:[{“值”:21.0,“测试”:“D”}]}
    23 产品C 2023-01-01 {“值”:[{“测试”:“A”,“值”:[{“值”:5,“测试”:“B”}]},{“值”:10,“测试”:“D”}]}
    24 产品D 2023-02-01 {“值”:[{“测试”:“A”,“值”:[{“值”:2,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    三十二 产品 E 2023-01-01 {“值”:[{“值”:15,“测试”:“F”}]}
    31 产品G 2023-02-01 {“值”:[{“测试”:“G”,“值”:[{“值”:7,“测试”:“H”}]}]}
    101 产品G 2023-02-01 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    401 产品 F 2023-03-03 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    402 产品 F 2023-03-03 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    with recursive r as(
       select 0 lvl,prg_id,name,dt,el1.value elem,position
          ,pars_col
       from df
       cross join json_array_elements(pars_col -> 'values') with ordinality AS el1(value,position)
      union all
       select lvl+1 lvl,prg_id,name,dt,el1.value elem,el1.position
          ,pars_col
       from r
       cross join json_array_elements(r.elem -> 'values') with ordinality AS el1(value,position)
    )
    select prg_id,name,dt
      ,sum(cast(elem ->>'value' as numeric)) as total
      -- ,elem ,elem ->>'value' elem_value,lvl,pars_col
    from r
    where elem::jsonb ? 'value'
    group by prg_id,name,dt
    order by prg_id,name,dt
    
    prg_id 姓名 日期 全部的
    1 产品 A 2023-01-01 8
    2 产品 B 2023-02-01 21.0
    23 产品C 2023-01-01 15
    24 产品D 2023-02-01 5
    31 产品G 2023-02-01 7
    三十二 产品 E 2023-01-01 15
    101 产品G 2023-02-01 12
    401 产品 F 2023-03-03 12
    402 产品 F 2023-03-03 二十九

    例如分组前的查询结果(部分展示)

    等级 prg_id 姓名 日期 元素 位置 pars_col
    0 1 产品 A 2023-01-01 {“测试”:“A”,“值”:[{“值”:8,“测试”:“B”}]} 1 {“值”:[{“测试”:“A”,“值”:[{“值”:8,“测试”:“B”}]}]}
    1 1 产品 A 2023-01-01 {“值”:8,“测试”:“B”} 1 {“值”:[{“测试”:“A”,“值”:[{“值”:8,“测试”:“B”}]}]}
    0 402 产品 F 2023-03-03 {“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]} 2 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]} ]}
    0 402 产品 F 2023-03-03 {“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]} 1 {“值”:[ {“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    1 402 产品 F 2023-03-03 {“值”:9,“测试”:“B”} 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    1 402 产品 F 2023-03-03 {“值”:3,“测试”:“E”} 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    1 402 产品 F 2023-03-03 {"值":14, "测试":"F"} 2 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    1 402 产品 F 2023-03-03 {“值”:[{“值”:3,“测试”:“E”}]} 3 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    2 402 产品 F 2023-03-03 {“值”:3,“测试”:“E”} 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}

    例如分组前的查询结果,但是最后的元素被过滤掉了

    prg_id 姓名 日期 元素 元素值 等级 pars_col
    1 产品 A 2023-01-01 {“值”:8,“测试”:“B”} 8 1 {“值”:[{“测试”:“A”,“值”:[{“值”:8,“测试”:“B”}]}]}
    2 产品 B 2023-02-01 {“值”:21.0,“测试”:“D”} 21.0 0 {“值”:[{“值”:21.0,“测试”:“D”}]}
    23 产品C 2023-01-01 {"值":10, "测试":"D"} 10 0 {“值”:[{“测试”:“A”,“值”:[{“值”:5,“测试”:“B”}]},{“值”:10,“测试”:“D”}]}
    23 产品C 2023-01-01 {“值”:5,“测试”:“B”} 5 1 {“值”:[{“测试”:“A”,“值”:[{“值”:5,“测试”:“B”}]},{“值”:10,“测试”:“D”}]}
    24 产品D 2023-02-01 {“值”:2,“测试”:“B”} 2 1 {“值”:[{“测试”:“A”,“值”:[{“值”:2,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    24 产品D 2023-02-01 {“值”:3,“测试”:“E”} 3 1 {“值”:[{“测试”:“A”,“值”:[{“值”:2,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    31 产品G 2023-02-01 {"值":7, "测试":"H"} 7 1 {“值”:[{“测试”:“G”,“值”:[{“值”:7,“测试”:“H”}]}]}
    三十二 产品 E 2023-01-01 {"值":15, "测试":"F"} 15 0 {“值”:[{“值”:15,“测试”:“F”}]}
    101 产品G 2023-02-01 {“值”:9,“测试”:“B”} 9 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    101 产品G 2023-02-01 {“值”:3,“测试”:“E”} 3 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    401 产品 F 2023-03-03 {“值”:9,“测试”:“B”} 9 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    401 产品 F 2023-03-03 {“值”:3,“测试”:“E”} 3 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”}]}]}
    402 产品 F 2023-03-03 {“值”:9,“测试”:“B”} 9 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    402 产品 F 2023-03-03 {“值”:3,“测试”:“E”} 3 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    402 产品 F 2023-03-03 {"值":14, "测试":"F"} 14 1 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}
    402 产品 F 2023-03-03 {“值”:3,“测试”:“E”} 3 2 {“值”:[{“测试”:“A”,“值”:[{“值”:9,“测试”:“B”}]},{“测试”:“D”,“值”:[{“值”:3,“测试”:“E”},{“值”:14,“测试”:“F”},{“值”:[{“值”:3,“测试”:“E”}]}]}]}

    小提琴

    附注:我们在这里不使用
    该值with ordinality。我留下它只是为了好玩,我并不是真的需要它。

    PPS
    最低请求类型。

    with recursive r as(
       select prg_id,name,dt,el1.value elem
       from df
       cross join json_array_elements(pars_col -> 'values') el1
      union all
       select prg_id,name,dt,el1.value elem
       from r
       cross join json_array_elements(r.elem -> 'values') el1
    )
    select prg_id,name,dt ,sum(cast(elem ->>'value' as numeric)) as total
    from r
    where elem::jsonb ? 'value'
    group by prg_id,name,dt
    order by prg_id,name,dt
    

    如果正在解析的字符串不包含任何类型的元素
    {"values": [{"value": 21.0, "test": "D"}]},
    它将根本不包含在输出中。

    • 1

相关问题

  • 通过 OUT 参数从过程结果输出

  • ON 关键字附近的语法错误 - SQL

  • 多表查询中的 Count() 聚合函数

  • 根据时间更改单元格中的日期

  • phpMyAdmin 中的错误 #1064 SQL 查询

  • Qt:包含变量的数据库查询

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5