如何使用PostgreSQL更新jsonb字符串?
我正在使用PostgreSQL 9.4.5。我想更新a如何使用PostgreSQL更新jsonb字符串?,json,postgresql,postgresql-9.4,jsonb,nosql,Json,Postgresql,Postgresql 9.4,Jsonb,Nosql,我正在使用PostgreSQL 9.4.5。我想更新ajsonb专栏 我的表格的结构如下: CREATE TABLE my_table ( gid serial PRIMARY KEY, "data" jsonb ); JSON字符串如下所示: {"files": [], "ident": {"id": 1, "country": null, "type ": "20"}} 以下SQL不执行此任务(语法错误-SQL状态=42601): 有没有办法做到这一点?我以前的解决方案依赖
jsonb
专栏
我的表格的结构如下:
CREATE TABLE my_table (
gid serial PRIMARY KEY,
"data" jsonb
);
JSON字符串如下所示:
{"files": [], "ident": {"id": 1, "country": null, "type ": "20"}}
以下SQL不执行此任务(语法错误-SQL状态=42601):
有没有办法做到这一点?我以前的解决方案依赖于9.5功能
我建议您要么使用下面的abelisto解决方案,要么使用pl/perlu、plpythonu或plv8js,用一种对json变体有更好支持的语言编写json变体。在第9.4页中,像
jsonb_set()
(9.5)这样的“简单”解决方案很不走运。您唯一的选择是解压缩JSON对象,进行更改并重新构建该对象。这听起来很麻烦,事实上确实如此:不管内置函数多么高级或复杂,JSON都很难操作
CREATE TYPE data_ident AS (id integer, country text, "type" integer);
UPDATE my_table
SET "data" = json_build_object('files', "data"->'files', 'ident', ident.j)::jsonb
FROM (
SELECT gid, json_build_object('id', j.id, 'country', 'Belgium', 'type', j."type") AS j
FROM my_table
JOIN LATERAL jsonb_populate_record(null::data_ident, "data"->'ident') j ON true) ident
WHERE my_table.gid = ident.gid;
在SELECT
子句中,将“数据”->“标识”
解压缩到记录中(您需要为其创建类型
结构)。然后,它被构建回一个带有新国家名称的JSON对象中。在UPDATE
中,将的“ident”
对象与的“files”
对象重新连接,并将整个对象转换为jsonb
一个纯粹的美的东西——只要速度不是你的东西……好的,有两个功能:
create or replace function set_jsonb_value(p_j jsonb, p_key text, p_value jsonb) returns jsonb as $$
select jsonb_object_agg(t.key, t.value) from (
select
key,
case
when jsonb_typeof(value) = 'object' then set_jsonb_value(value, p_key, p_value)
when key = p_key then p_value
else value
end as value from jsonb_each(p_j)) as t;
$$ language sql immutable;
第一个仅更改现有密钥的值,而不考虑密钥路径:
postgres=# select set_jsonb_value(
'{"files": [], "country": null, "ident": {"id": 1, "country": null, "type ": "20"}}',
'country',
'"foo"');
set_jsonb_value
--------------------------------------------------------------------------------------
{"files": [], "ident": {"id": 1, "type ": "20", "country": "foo"}, "country": "foo"}
(1 row)
第二种方法是使用指定的路径更改现有密钥的值,或者在路径不存在时创建它:
postgres=# select set_jsonb_value(
'{"files": [], "country": null, "ident": {"id": 1, "type ": "20"}}',
'{ident,country}'::text[],
'"foo"');
set_jsonb_value
-------------------------------------------------------------------------------------
{"files": [], "ident": {"id": 1, "type ": "20", "country": "foo"}, "country": null}
(1 row)
postgres=# select set_jsonb_value(
'{"files": [], "country": null, "ident": {"id": 1, "type ": "20"}}',
'{ident,foo,bar,country}'::text[],
'"foo"');
set_jsonb_value
-------------------------------------------------------------------------------------------------------
{"files": [], "ident": {"id": 1, "foo": {"bar": {"country": "foo"}}, "type ": "20"}, "country": null}
(1 row)
希望对使用PostgreSQL的人有所帮助<9.5免责声明:在PostgreSQL 9.5上测试
更新my_表集“data”=jsonb_集(“data”、“{”ident“,”country“}”和“,”比利时“)
实际重复:我同意,但你提到的帖子中的问题是关于json
类型(而不是jsonb
)。答案通常指的是jsonb
。@Abelisto:您的查询返回错误消息:函数jsonb_集(jsonb,未知,未知)不存在jsonb_set()
函数对v来说似乎是新函数。是的,我错过了postgresql-9.4
标签<9.5版本中引入了code>jsonb_集功能。肮脏但简单的方式:。。。设置“data”=regexp_replace(“data”::text,“country”:[^,^}]+',“country”:“belling”)::jsonb
您的查询返回错误消息:fonction jsonb_build_object(未知,未知)不存在抱歉,误读了文档,应该是json_build_object,然后将最终结果强制转换到jsonb。editing.hmmm | |也是仅9.5版本。IMO您的解决方案的主要缺点是,您在重建整个对象时并没有注意到其可能不同的初始结构。
create or replace function set_jsonb_value(p_j jsonb, p_path text[], p_value jsonb) returns jsonb as $$
select jsonb_object_agg(t.key, t.value) from (
select
key,
case
when jsonb_typeof(value) = 'object' then set_jsonb_value(value, p_path[2:1000], p_value)
when key = p_path[1] then p_value
else value
end as value from jsonb_each(p_j)
union all
select
p_path[1],
case
when array_length(p_path,1) = 1 then p_value
else set_jsonb_value('{}', p_path[2:1000], p_value) end
where not p_j ? p_path[1]) as t;
$$ language sql immutable;
postgres=# select set_jsonb_value(
'{"files": [], "country": null, "ident": {"id": 1, "type ": "20"}}',
'{ident,country}'::text[],
'"foo"');
set_jsonb_value
-------------------------------------------------------------------------------------
{"files": [], "ident": {"id": 1, "type ": "20", "country": "foo"}, "country": null}
(1 row)
postgres=# select set_jsonb_value(
'{"files": [], "country": null, "ident": {"id": 1, "type ": "20"}}',
'{ident,foo,bar,country}'::text[],
'"foo"');
set_jsonb_value
-------------------------------------------------------------------------------------------------------
{"files": [], "ident": {"id": 1, "foo": {"bar": {"country": "foo"}}, "type ": "20"}, "country": null}
(1 row)