更新关系表时:
CREATE TABLE foo ( id serial primary key, credit numeric);
UPDATE foo SET bar = bar + $1 WHERE id = $2;
然而,JSON中的等价物不起作用:
CREATE TABLE foo ( id serial primary key, data json);
UPDATE foo SET data->'bar' = data->'bar' + $1 WHERE id = $2;
我得到的错误是error: syntax error at or near "->"
- 这是相当模糊的。
我该怎么做?
我正在使用postgres 9.3.4
根据@ GordonLinoff在下面的评论,我创建了一个功能请求:https://postgresql.uservoice.com/forums/21853-general/suggestions/6466818-create-update-delete-on-json-keys
如果您也想要这个功能,可以投票。
答案 0 :(得分:12)
根据@ joonas.fi和pozs's的答案,我想出了一个更“美丽”的解决方案
UPDATE foo
SET data = jsonb_set(data, '{bar}', (COALESCE(data->>'bar','0')::int + 1)::text::jsonb)
WHERE id = 1;
答案 1 :(得分:6)
您可以使用jsonb
执行此操作,至少使用Postgres 9.5.2。
鉴于下表:
CREATE TABLE users (id INT, counters JSONB NOT NULL DEFAULT '{}');
使用样本数据:
INSERT INTO users (id, counters) VALUES (1, '{"bar": 0}');
SELECT * FROM users;
id | counters
----+------------
1 | {"bar": 0}
您可以原子地增加JSON中的“bar”键:
UPDATE users SET counters = counters || CONCAT('{"bar":', COALESCE(counters->>'bar','0')::int + 1, '}')::jsonb WHERE id = 1;
SELECT * FROM users;
id | counters
----+------------
1 | {"bar": 1}
它不漂亮但它有效。
这里分为几步:
您可以通过jsonb
jsonb对象将OR
中的密钥设置为显式值:
UPDATE users SET counters = counters || '{"bar": 314}'::jsonb WHERE id = 1;
SELECT * FROM users;
id | counters
----+--------------
1 | {"bar": 314}
现在剩下要做的就是在CONCAT()的帮助下动态构建字符串,同时演示一个未定义的键递增(27)(在COALESCE()的帮助下默认初始值):
UPDATE users SET counters = counters || CONCAT('{"foo":', COALESCE(counters->>'foo','0')::int + 27, '}')::jsonb WHERE id = 1;
SELECT * FROM users;
id | counters
----+-------------------------
1 | {"bar": 314, "foo": 27}
鲍勃是你的叔叔。 :)
答案 2 :(得分:0)
嵌套的JSONB数据:
发件人:
table_name.data_col = {"a": {"b": {"c": 1}}} // JSONB
收件人:
table_name.data_col = {"a": {"b": {"c": 2}}} // JSONB
使用此:
UPDATE
table_name
SET
data_col = jsonb_set(
data_col,
'{a,b,c}',
(
COALESCE(
data_col#>'{a,b,c}', '0'
):: int + 1
):: text :: jsonb
)
WHERE
id = '<id>';
其中table_name
是表名,data_col
是您的JSONB
列
注释:
decrement
等使用- 1
操作。