如何使用postgresql更新一行中字典的多个值

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

我有一个包含两列和以下数据的表格。我坚持这个表的结构,并且不可能对其进行修改,因为公司已经显着增长,并且很多功能都依赖于该特定格式。

id(长) 步骤(jsonb)
1 {“uuid1”:{“value1”:[10]},“uuid2”:{“value45”:1}}
2 {“uuid3”:{“值1”:[1]},“uuid4”:{“值1”:[3]}

我想更新这些数据以获得下表(将“value1”中的数组转换为标量):

id(长) 步骤(jsonb)
1 {“uuid1”:{“value1”:10},“uuid2”:{“value45”:1}}
2 {“uuid3”:{“值1”:1},“uuid4”:{“值1”:3}

问题出在顶级字典的 uuid 键上。当单行中有多个“value1”键时,我无法获得预期的结果。

感谢这个问题,我收到以下请求:

with s AS (
    SELECT
        a.id,
        ARRAY[key,'value1'] as path,
        value#>'{value1}'->0 as value
    FROM a, jsonb_each(steps)
    WHERE (value->'value1') IS NOT NULL
      AND value#>'{value1}'->0 IS NOT NULL
)
UPDATE a
SET steps = jsonb_set(a.steps, s.path, s.value)
FROM s
WHERE s.id = a.id;

s 表有 3 行:

id(长) 路径 价值
1 “uuid1” 10
2 “uuid3” 1
2 “uuid4” 3

但是,这一次只能修改一条记录。如何修改我的请求,以便更新单行中的所有“value1”嵌套键?

感谢您的宝贵时间。

sql json postgresql sql-update jsonb
3个回答
1
投票

查询有效,但它看起来像一个怪物。为了避免此类查询,您需要规范化您的数据库,正如评论部分中提到的那样。

演示

主要思想:

  1. 检测具有需要更新的
    value1
    值的对。
  2. 从步骤 1 中的对中检测密钥。
  3. 使用之前检测到的键值对构建更新的
    jsonb
    片段。
  4. 从原始
    jsonb
    需要更新的字段键中减去,因此我们得到原始
    jsonb
    的“不可变”部分。
  5. 构建最终的
    jsonb
    :将更新的
    jsonb
    片段与不可变片段合并(分别为步骤 3 和 4)。

需要注意的是,最终

jsonb
中键值对的顺序可能与原始的不同。

-- final query
with tmp as (
  with
  -- jsonb presented as key-value pairs with 'value1'
  disjointed_data as (select
        test_data.id,
        key as key,
        value#>'{value1}'->0 as value
    from test_data, jsonb_each(steps)
    where (value->'value1') is not null and value#>'{value1}'->0 is not null
  ),
  -- keys with 'value1' to update
  aggr_keys as (select
        test_data.id,
        array_agg(key) as keys
    from test_data, jsonb_each(steps)
    where (value->'value1') is not null and value#>'{value1}'->0 is not null
  group by test_data.id
  ),
  -- prefinal jsonb parts to aggregate
  prefinal_jsonb_parts as (select
      dd.id,
      jsonb_build_object(dd.key, json_build_object('value1', dd.value)) as upd_part
    from disjointed_data as dd
    
    union

    select test_data.id, 
      steps - aggr_keys.keys as unchanged_part
    from test_data
    join aggr_keys on aggr_keys.id = test_data.id
  )
select pp.id, jsonb_object_agg(key, value) as result_jsonb
from prefinal_jsonb_parts as pp, jsonb_each(pp.upd_part)
group by pp.id
order by pp.id -- not necessary operation
)
update test_data
set steps = result_jsonb
from tmp
where test_data.id = tmp.id;

0
投票

使用两个子查询与

jsonb_each
:

select t.id, (select jsonb_object_agg(k.key, (select jsonb_object_agg(k1.key, 
     case when jsonb_typeof(k1.value) = 'array' 
       then (k1.value ->> 0)::jsonb else k1.value::jsonb end) 
   from jsonb_each(k.value) k1)) 
  from jsonb_each(t.steps) k) 
from tbl t

看小提琴


0
投票

首先在将数组转换为值时进行扁平化(

fl
子查询),然后重新聚合。

select id, jsonb_object_agg(l1k, jsonb_build_object(l2k, v)) steps
from 
(
 select id, l1.key l1k, l2.key l2k, 
       case when jsonb_typeof(l2.value)='array' then l2.value[0] else l2.value end v 
 from the_table,
 lateral jsonb_each(steps) l1,
 lateral jsonb_each(l1.value) l2
) fl
group by id;

DB-fiddle 演示

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