如何在JSON键上的postgres更新语句中增加值

时间:2014-09-21 09:49:29

标签: sql json postgresql sql-update postgresql-9.3

更新关系表时:

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

如果您也想要这个功能,可以投票。

3 个答案:

答案 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 操作。
  • PostgreSQL docs用于json操作非常有用