我的表中有一个列类型文本,其中包含 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';
下面的方法使用
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