使用postgresql 9.3我可以选择JSON数据类型的特定字段,但如何使用UPDATE修改它们?我在postgresql文档或网上任何地方都找不到这样的例子。我尝试了一些显而易见的方法:
postgres=# create table test (data json);
CREATE TABLE
postgres=# insert into test (data) values ('{"a":1,"b":2}');
INSERT 0 1
postgres=# select data->'a' from test where data->>'b' = '2';
?column?
----------
1
(1 row)
postgres=# update test set data->'a' = to_json(5) where data->>'b' = '2';
ERROR: syntax error at or near "->"
LINE 1: update test set data->'a' = to_json(5) where data->>'b' = '2...
例如,我的字符串是这样的:
{" a1 ":{“a11”:“x”,“a22”:“y”、“a33”:“z”}}
我使用临时表更新jsons,这对于相当小的数据量(<1.000.000)已经足够了。我找到了另一条路,但后来去度假了,就忘了……
所以。查询将是这样的:
with temp_table as (
select
a.id,
a->'a1'->>'a11' as 'a11',
a->'a1'->>'a22' as 'a22',
a->'a1'->>'a33' as 'a33',
u1.a11updated
from foo a
join table_with_updates u1 on u1.id = a.id)
update foo a
set a = ('{"a1": {"a11": "'|| t.a11updated ||'",
"a22":"'|| t.a22 ||'",
"a33":"'|| t.a33 ||'"}}')::jsonb
from temp_table t
where t.id = a.id;
它与string的关系比json更大,但它是有效的。基本上,它将所有数据拉到临时表中,在用备份的数据插入concat漏洞时创建一个字符串,并将其转换为jsonb。
Json_set可能更有效,但我仍然掌握了它的窍门。当我第一次尝试使用它时,我完全把弦弄乱了……
下面的plpython代码片段可能会派上用场。
CREATE EXTENSION IF NOT EXISTS plpythonu;
CREATE LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION json_update(data json, key text, value text)
RETURNS json
AS $$
import json
json_data = json.loads(data)
json_data[key] = value
return json.dumps(json_data, indent=4)
$$ LANGUAGE plpythonu;
-- Check how JSON looks before updating
SELECT json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
FROM sc_server_centre_document WHERE record_id = 35 AND template = 'CFRDiagnosis';
-- Once satisfied update JSON inplace
UPDATE sc_server_centre_document SET content = json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
WHERE record_id = 35 AND template = 'CFRDiagnosis';
你觉得这个解决办法怎么样?
它将添加新值或更新现有值。
编辑:编辑后使其与null和空对象一起工作
Edit2:编辑使它与对象中的对象一起工作…
create or replace function updateJsonb(object1 json, object2 json)
returns jsonb
language plpgsql
as
$$
declare
result jsonb;
tempObj1 text;
tempObj2 text;
begin
tempObj1 = substr(object1::text, 2, length(object1::text) - 2); --remove the first { and last }
tempObj2 = substr(object2::text, 2, length(object2::text) - 2); --remove the first { and last }
IF object1::text != '{}' and object1::text != 'null' and object1::text != '[]' THEN
result = ('{' || tempObj1 || ',' || tempObj2 || '}')::jsonb;
ELSE
result = ('{' || tempObj2 || '}')::jsonb;
END IF;
return result;
end;
$$;
用法:
update table_name
set data = updatejsonb(data, '{"test": "ok"}'::json)
我为自己写了一个小函数,在Postgres 9.4中递归地工作。下面是函数(我希望它对你有用):
CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
result JSONB;
v RECORD;
BEGIN
IF jsonb_typeof(val2) = 'null'
THEN
RETURN val1;
END IF;
result = val1;
FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP
IF jsonb_typeof(val2->v.key) = 'object'
THEN
result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
ELSE
result = result || jsonb_build_object(v.key, v.value);
END IF;
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql;
下面是使用示例:
select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
jsonb_update
---------------------------------------------------------------------
{"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
(1 row)
正如你所看到的,它深入分析并在需要的地方更新/添加值。