将 json 对象的所有值与 postgres 9.6 相乘

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

我的表中有一个列类型文本,其中包含 json 对象,如下所示:

{{"name":"MyName","age":10.0, "attribut":{"attack":"20","defence":30},{"name":"yourName","age":20.0}}

我想将所有数字

*2
相乘为:

{{"name":"MyName","age":20.0, "attribut":{"attack":"40","defence":60},{"name":"yourName","age":40.0}}

但是我不知道json对象有多深,也不知道键,它不规则。


我尝试了很多不同的事情,但没有成功,(请不要否决我的问题),所以这是我向你们所有人提出的问题: 如何将 json 对象的所有数值相乘?


我失败的尝试是查看 jsonb_* 并替换函数:

暂定1: 我尝试获取列中 {key1,key2} 值的所有路径作为子请求,并将其与其他请求组合,但我所有的测试都失败了,避免了密钥不存在时的错误...

SQL 错误 [22023]:错误:无法在标量上调用 jsonb_object_keys

SELECT keys1.*, keys2.*, keys3.*, keys4.*
FROM schema.table, 
    jsonb_object_keys(schema.table.values_detail::jsonb) AS keys1 (key1),
    jsonb_object_keys(schema.table.values_detail::jsonb -> keys1 ) AS keys2 (key2),
    jsonb_object_keys(schema.table.values_detail::jsonb -> keys1 -> keys2 ) AS keys3 (key3)
WHERE id = '1afd3d7e-d05v-4d63-9cef-8fb9f6f9514f';


UPDATE
    schema.table
SET
    values_detail = (
    SELECT
        jsonb_object_agg(CASE
                  WHEN jsonb_typeof(values_detail::jsonb #> paths) = 'number'
                  THEN jsonb_set(values_detail::jsonb, ... ))
       END)
    FROM
        sub-request as paths
    )::text
WHERE id = '1afd3d7e-d05v-4d63-9cef-8fb9f6f9514f';

暂定2:然后我尝试,仅获取文本的数字,然后将数字相乘,然后将它们替换回来,但代码不接受它,正则表达式匹配:无法转换为int。

SQL 错误 [22P02]:错误:整数输入语法无效:“”

SELECT 
    values_detail AS origin-json,
 
    regexp_replace(
        values_detail,
        ':([0-9]+)',
        CONCAT(':', 
            CAST( (CAST('\1' AS int)*2) AS text)
        )
        , 'ig'
    ) AS transformed-json
 
FROM schema.table
WHERE id = '1afd3d7e-d05v-4d63-9cef-8fb9f6f9514f';
sql json postgresql-9.6
1个回答
0
投票

下面的方法使用

cte
从左到右迭代字符串,当整数作为特定键的值出现时使用整数,并将其双精度结果连接到正在运行的占位符字符串,并附加非整数字符如果未找到整数,则为占位符:

with recursive cte(id, s, v) as (
   select t.id, '', t.values_detail from tbl t
   union all
   select c.id, concat(c.s, case when regexp_substr(c.v, '^\:\d+') is not null then 
       ':'||(regexp_substr(substr(c.v, 2), '^\d+')::int * 2)::text
    when regexp_substr(c.v, '^:"\d+"') is not null then
        ':"'||(regexp_substr(substr(c.v, 3), '^\d+')::int * 2)::text||'"'
    else substr(c.v, 1, 1) end),
    case when regexp_substr(c.v, '^\:\d+') is not null then regexp_replace(c.v, '^\:\d+', '')
    when regexp_substr(c.v, '^:"\d+"') is not null then regexp_replace(c.v, '^:"\d+"', '')
    else substr(c.v, 2) end
  from cte c where length(c.v) > 0
)
update tbl set values_detail = c.s from cte c where c.id = tbl.id and length(c.v) = 0

看小提琴

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