【问题标题】:How to update table based on a json map?如何根据 json 映射更新表?
【发布时间】:2017-08-19 09:11:04
【问题描述】:

如果我有这张桌子

CREATE TABLE tmp (
    a integer,
    b integer,
    c text
);
INSERT INTO tmp (a, b, c) VALUES (1, 2, 'foo');

还有这个json:

{
    "a": 4,
    "c": "bar"
}

键映射到列名,值是新值。

如何在不触及不在地图中的列的情况下更新tmp 表?

我想过构造一个可以在 pl/pgsql 中执行的 SQL update 语句的动态字符串,但似乎必须预先确定传递给 USING 的参数数量。但是实际的参数数量是由 map 中的 key 数量决定的,这是动态的,所以这似乎是一个死胡同。

我知道我可以在循环键时使用多个更新语句更新表,但问题是我为表设置了一个触发器,它将修改表(通过将更改的列插入另一个表),因此必须在单个 update 语句中更新列。

我想知道是否可以使用 json map 动态更新表?

【问题讨论】:

  • @klin 谢谢,但不确定它是否有效,如果我只是从地图中提取所有可能的键,在我的示例中,(map->>'b')::integer 将返回null,并且在更新语句中,不会不是用null 更新b 吗?

标签: database postgresql


【解决方案1】:

使用coalesce()。示例表:

drop table if exists my_table;
create table my_table(id int primary key, a int, b text, c date);
insert into my_table values (1, 1, 'old text', '2017-01-01');

和查询:

with jsondata(jdata) as (
    values ('{"id": 1, "b": "new text"}'::jsonb)
)

update my_table set
    a = coalesce((jdata->>'a')::int, a),
    b = coalesce((jdata->>'b')::text, b),
    c = coalesce((jdata->>'c')::date, c)
from jsondata
where id = (jdata->>'id')::int;

select * from my_table;

 id | a |    b     |     c      
----+---+----------+------------
  1 | 1 | new text | 2017-01-01
(1 row) 

【讨论】:

  • 更通用的解决方案:update my_table set (a, b, c) = (select a, b, c from jsonb_populate_record(null::my_table, to_jsonb(my_table) || jdata)) ...
猜你喜欢
  • 2016-12-09
  • 2021-11-30
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 2020-08-23
  • 1970-01-01
  • 1970-01-01
  • 2019-04-15
相关资源
最近更新 更多