我有一个包含两列和以下数据的表格。我坚持这个表的结构,并且不可能对其进行修改,因为公司已经显着增长,并且很多功能都依赖于该特定格式。
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”嵌套键?
感谢您的宝贵时间。
查询有效,但它看起来像一个怪物。为了避免此类查询,您需要规范化您的数据库,正如评论部分中提到的那样。
主要思想:
value1
值的对。jsonb
片段。jsonb
需要更新的字段键中减去,因此我们得到原始 jsonb
的“不可变”部分。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;
使用两个子查询与
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
首先在将数组转换为值时进行扁平化(
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;