kis*_*ram 8 postgresql update json postgresql-10 json-path
我在 Postgres 表中有一个jsonb
列。它包含以下数据:data
my_table
[
{"id":"1","status":"test status1","updatedAt":"1571145003"},
{"id":"2","status":"test status2","updatedAt":"1571145323"}
]
Run Code Online (Sandbox Code Playgroud)
我想updatedAt
使用一个查询更新该数组中所有对象的键。我试过:
update my_table set data = data || '{"updatedAt": "1571150000"}';
Run Code Online (Sandbox Code Playgroud)
上面的查询在数组中添加了一个新对象,如下所示:
[
{"id":"1","status":"test status1","updatedAt":"1571145003"},
{"id":"2","status":"test status2","updatedAt":"1571145323"},
{"updatedAt":"1571150000"}
]
Run Code Online (Sandbox Code Playgroud)
我想要的输出如下:
[
{"id":"1","status":"test status1","updatedAt":"1571150000"},
{"id":"2","status":"test status2","updatedAt":"1571150000"}
]
Run Code Online (Sandbox Code Playgroud)
我也尝试过jsonb_set()
,但这需要第二个参数是数组索引。我无法确定数组中 JSON 对象的数量。
如果可以通过自定义函数解决这个问题,也很好。
第一个 cte 取消数组的所有元素的嵌套,第二个 cte 更新每个元素,然后简单地更新再次构建数组的原始表。
with ct as
(
select id, jsonb_array_elements(data) dt
from t
)
, ct2 as
(
select id, jsonb_set(dt, '{updatedAt}', '"1571150000"', false) dt2
from ct
)
update t
set data = (select jsonb_agg(dt2) from ct2 where ct2.id = t.id);
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)select * from t;
编号 | 数据 -: | :---------------------------------------------------------------- -------------------------------------------------- -------------------------------- 1 | [{"id": "1", "status": "测试状态1", "updatedAt": "1571150000"}, {"id": "2", "status": "测试状态2", "updatedAt": “1571150000”}]
db<>在这里摆弄
您声明了 Postgres 10,McNets 为其提供了有效的解决方案。如果没有 CTE,它的效率应该会稍微高一些,因为在 Postgres 12 之前无法内联这些 CTE:
UPDATE tbl
SET data = (
SELECT jsonb_agg(jsonb_set(d, '{updatedAt}', '"15711500000"', false))
FROM jsonb_array_elements(data) d
);
Run Code Online (Sandbox Code Playgroud)
jsonb_set()
很方便,但操作仍然效率低下,而某些行实际上并不需要更新。此查询为每一行写入一个新版本。看:
仅更新实际更改的行会更有效。更好的是,首先确定那些有指数支持的人。在 Postgres 10 中这并不简单(需要定制的表达式索引)。自Postgres 12使用SQL/JSON路径语言以来,更加简单和高效:
UPDATE tbl
SET data = (
SELECT jsonb_agg(jsonb_set(dt, '{updatedAt}', '"15711500000"', false))
FROM jsonb_array_elements(data) dt
)
WHERE data @? '$.updatedAt ? (@ != "1571150000")';
Run Code Online (Sandbox Code Playgroud)
添加的内容WHERE data @? '$.updatedAt ? (@ != "1571150000")'
基本上是这样的:
'查看顶层的键“updatedAt”(在所有数组元素中)并检查它们中是否有任何一个不等于“1571150000”;当(且仅当)找到这样的密钥时返回 true。
标识具有索引支持的合格行。手册:
此外,GIN 索引支持
@@
和@?
运算符,用于执行jsonpath
匹配。
!=
比 更难支持==
。但指数支持仍然可以产生巨大的影响。
归档时间: |
|
查看次数: |
11859 次 |
最近记录: |