简体   繁体   English

如何在 JSON 密钥的 postgres 更新语句中增加值

[英]How to increment value in postgres update statement on JSON key

When updating a relational table:更新关系表时:

CREATE TABLE foo ( id serial primary key, credit numeric);
UPDATE foo SET bar = bar + $1 WHERE id = $2;

However the equivalent in JSON doesn't work:但是 JSON 中的等效项不起作用:

CREATE TABLE foo ( id serial primary key, data json);
UPDATE foo SET data->'bar' = data->'bar' + $1 WHERE id = $2;

The error I get is error: syntax error at or near "->" - which is rather ambiguous.我得到的error: syntax error at or near "->"error: syntax error at or near "->" - 这是相当不明确的。

How do I do this?我该怎么做呢?

I am using postgres 9.3.4我正在使用 postgres 9.3.4


In light of @GordonLinoff's comment below, I have created a feature request: https://postgresql.uservoice.com/forums/21853-general/suggestions/6466818-create-update-delete-on-json-keys根据下面@GordonLinoff 的评论,我创建了一个功能请求: https ://postgresql.uservoice.com/forums/21853-general/suggestions/6466818-create-update-delete-on-json-keys

You can vote on it if you would like this feature too.如果您也喜欢此功能,可以对其进行投票。

Based on @joonas.fi's and pozs's answers, I came up with a slightly more 'beautiful' solution基于@joonas.fi 和pozs 的回答,我想出了一个稍微“漂亮”的解决方案

UPDATE foo 
SET data = jsonb_set(data, '{bar}', (COALESCE(data->>'bar','0')::int + 1)::text::jsonb)
WHERE id = 1;

You can do this with jsonb , at least with Postgres 9.5.2.你可以用jsonb做到这jsonb ,至少用 Postgres 9.5.2。

Given the following table:鉴于下表:

CREATE TABLE users (id INT, counters JSONB NOT NULL DEFAULT '{}');

With sample data:使用样本数据:

INSERT INTO users (id, counters) VALUES (1, '{"bar": 0}');

SELECT * FROM users;

 id |    counters
----+------------
  1 | {"bar": 0}

You can increment "bar" key in JSON atomically:您可以原子地增加 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}

It's not beautiful but it works.它不漂亮,但它有效。

Here it is broken down in steps:这里分为几个步骤:

You can set a key in jsonb to an explicit value by OR 'ing the jsonb objects:您可以设置一键jsonb通过明确的值OR “荷兰国际集团的jsonb对象:

UPDATE users SET counters = counters || '{"bar": 314}'::jsonb WHERE id = 1;

SELECT * FROM users;

 id |     counters
----+--------------
  1 | {"bar": 314}

Now all that's left to do is build the string dynamically with the help of CONCAT(), at the same time demonstrating incrementing (by 27) an undefined key (defaulting initial value with help of COALESCE() ):现在剩下要做的就是在 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}

Bob's your uncle.鲍勃是你的叔叔。 :) :)

Nested JSONB data:嵌套的 JSONB 数据:

From:从:

table_name.data_col = {"a": {"b": {"c": 1}}} // JSONB

To:到:

table_name.data_col = {"a": {"b": {"c": 2}}} // JSONB

Use this:用这个:

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>';

Where table_name is your table name and data_col is your JSONB column其中table_name是您的表名,而data_col是您的JSONB

Notes:笔记:

  • If not obvious you can also decrement using - 1 etc for other operations.如果不明显,您还可以使用- 1decrement其他操作。
  • The PostgreSQL docs for json operations are super helpful用于 json 操作的PostgreSQL 文档非常有用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM