Art*_*emP 1 postgresql update json postgresql-9.5
我有一个具有以下定义的表:
create table json_test (
filter_data jsonb);
Run Code Online (Sandbox Code Playgroud)
我插入这样的值:
'{"task_packets": [
{
"state": "PROCEEDING",
"task_id": 1001
},
{
"state": "REVERTING",
"task_id": 1002
}
]}'
Run Code Online (Sandbox Code Playgroud)
现在我想将此jsonb
列更新为:
'{"task_packets": [
{
"state": "DONE",
"task_id": 1001
},
{
"state": "REVERTING",
"task_id": 1002
}
]}'
Run Code Online (Sandbox Code Playgroud)
即我想使用指定的task_id
内部 task_packets 数组更改值的状态。我建议以某种方式将jsonb_set()
函数与#-
运算符结合使用(首先从数组中删除值,然后使用更新的状态附加到它)。
我该怎么做?
就像我评论的那样,使用规范化的数据库布局会更有效,像这样的表
CREATE TABLE task_packets (
task_id int PRIMARY KEY
, state text NOT NULL
-- or: state_id int NOT NULL REFERENCES state(state_id) ...
);
Run Code Online (Sandbox Code Playgroud)
除此之外,我们可以有一个 PK 约束来强制执行唯一的task_id
数字。而UPDATE
你想要的是微不足道的。
但是要回答这个问题:
至SELECT
:
SELECT *
FROM json_test jt
, LATERAL (
SELECT jsonb_set(filter_data
, '{task_packets}'
, jsonb_agg(CASE WHEN elem->>'task_id' = '1001'
THEN jsonb_set(elem, '{state}', to_jsonb(text 'DONE'))
ELSE elem
END)) AS filter_data_new
FROM jsonb_array_elements(filter_data->'task_packets') elem
) tp
WHERE jt.filter_data @> '{"task_packets": [{"task_id": 1001}]}';
Run Code Online (Sandbox Code Playgroud)
我建议使用LATERAL
join,其中包括排除多个匹配行在普通连接中可能错误地混在一起的可能性。
至UPDATE
:
UPDATE json_test
SET filter_data =
(
SELECT jsonb_set(filter_data
, '{task_packets}'
, jsonb_agg(CASE WHEN elem->>'task_id' = '1001'
THEN jsonb_set(elem, '{state}', to_jsonb(text 'DONE'))
ELSE elem
END))
FROM jsonb_array_elements(filter_data->'task_packets') elem
)
WHERE filter_data @> '{"task_packets": [{"task_id": 1001}]}';
Run Code Online (Sandbox Code Playgroud)
同样可以用来实现相关子查询中UPDATE
(或在SELECT
为好)。
为了使大表的速度更快,请确保有一个合适的index,最好是一个jsonb_path_ops
索引:
归档时间: |
|
查看次数: |
17061 次 |
最近记录: |