【问题标题】:How to increment value in postgres update statement on JSON key如何在 JSON 键的 postgres 更新语句中增加值
【发布时间】:2014-11-15 11:11:27
【问题描述】:

更新关系表时:

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

如果你也喜欢这个功能,你可以投票。

【问题讨论】:

  • 我不认为你可以用update 做你想做的事。看到这个问题:stackoverflow.com/questions/18209625/….
  • @GordonLinoff 嗯 - 看起来像 CRUD,postgres 只支持对 JSON 类型属性的读取操作?这似乎是 postgres 对 JSON 支持的一个相当大的差距;有没有计划增加对此的支持,还是我们应该坚持使用 postgres 作为关系数据库(需要创建/更新/删除)?
  • 我们是否应该坚持使用 postgres 作为关系数据库? PostgreSQL 一个关系型数据库。请注意,JSON 旨在作为一种传输格式,而 PostgreSQL 9.3 存储的是 JSON(文本)而不是对象。它只会是一个评估过的对象。我认为 PostgreSQL 在读取属性方面已经走得很远,它是一种关系 DBMS,而不是像 Javascript 或 Python 这样的过程语言。 9.4 扩展了对 JSON 的支持,并且考虑到一些(IMO 被误导)用户希望 JSON 取代规范化和良好设计的 JSON 需求,我认为它可能会走得更远。

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


【解决方案1】:

根据@joonas.fi 和pozs's 的回答,我想出了一个更“漂亮”的解决方案

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

【讨论】:

    【解决方案2】:

    您可以使用 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}
    

    它并不漂亮,但它有效。

    这里按步骤分解:

    您可以通过OR'ing jsonb 对象将jsonb 中的键设置为显式值:

    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}
    

    鲍勃是你的叔叔。 :)

    【讨论】:

      【解决方案3】:

      嵌套 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 等其他 操作。
      • 用于 json 操作的 PostgreSQL docs 非常有用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多