使用postgresql 9.3我可以选择JSON数据类型的特定字段,但如何使用UPDATE修改它们?我在postgresql文档或网上任何地方都找不到这样的例子。我尝试了一些显而易见的方法:

postgres=# create table test (data json);
CREATE TABLE
postgres=# insert into test (data) values ('{"a":1,"b":2}');
INSERT 0 1
postgres=# select data->'a' from test where data->>'b' = '2';
 ?column?
----------
 1
(1 row)
postgres=# update test set data->'a' = to_json(5) where data->>'b' = '2';
ERROR:  syntax error at or near "->"
LINE 1: update test set data->'a' = to_json(5) where data->>'b' = '2...

当前回答

select * from pg_settings where name = 'deadlock_timeout';
begin;
create temp table a2(data jsonb);
insert into a2 values('{
    "key0": {
        "key01": "2018-05-06T12:36:11.916761+00:00",
        "key02": "DEFAULT_WEB_CONFIGURATION",
    "key1": {
        "key11": "Data System",
        "key12": "<p>Health,<p>my address<p>USA",
        "key13": "*Please refer to main screen labeling"
    }
}}'::jsonb);
commit;

嵌套的jsonb结构更新。可应用于删除。

update a2 set data =
    data::jsonb #-  '{key0, key1, key13}'
        || '{"key13":"screen labeling"}'::jsonb
returning *;

其他回答

select * from pg_settings where name = 'deadlock_timeout';
begin;
create temp table a2(data jsonb);
insert into a2 values('{
    "key0": {
        "key01": "2018-05-06T12:36:11.916761+00:00",
        "key02": "DEFAULT_WEB_CONFIGURATION",
    "key1": {
        "key11": "Data System",
        "key12": "<p>Health,<p>my address<p>USA",
        "key13": "*Please refer to main screen labeling"
    }
}}'::jsonb);
commit;

嵌套的jsonb结构更新。可应用于删除。

update a2 set data =
    data::jsonb #-  '{key0, key1, key13}'
        || '{"key13":"screen labeling"}'::jsonb
returning *;

遗憾的是,我没有在文档中找到任何东西,但您可以使用一些变通方法,例如您可以编写一些扩展函数。

例如,在Python中:

CREATE or REPLACE FUNCTION json_update(data json, key text, value json)
returns json
as $$
from json import loads, dumps
if key is None: return data
js = loads(data)
js[key] = value
return dumps(js)
$$ language plpython3u

然后

update test set data=json_update(data, 'a', to_json(5)) where data->>'b' = '2';

我发现以前的答案更适合有经验的PostgreSQL用户。这是给初学者的:

假设你有一个JSONB类型的表列,值如下:

{
    "key0": {
        "key01": "2018-05-06T12:36:11.916761+00:00",
        "key02": "DEFAULT_WEB_CONFIGURATION",
        
    "key1": {
        "key11": "Data System",
        "key12": "<p>Health,<p>my address<p>USA",
        "key13": "*Please refer to main screen labeling"
    }
}

让我们假设我们想在行中设置一个新值:

"key13": "*Please refer to main screen labeling"

取而代之的是放置值:

"key13": "See main screen labeling"

我们使用json_set()函数将一个新值赋给key13

jsonb_set()的参数

jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])

在“target”-我将放置jsonb column-name(这是正在修改的表列)

"path"-是指向(包括)我们要覆盖的键的"json keys路径"

"new_value" -这是我们分配的新值

在我们的例子中,我们想要更新位于key1下的key13的值(key1 -> key13):

因此路径语法是:'{key1,key13}' (路径是最棘手的部分-因为教程是可怕的)

jsonb_set(jsonb_column,'{key1,key13}','"See main screen labeling"')

即使下面的函数不能满足这个请求(函数json_object_agg在PostgreSQL 9.3中不可用),下面的函数对于任何为PostgreSQL 9.4寻找||运算符的人来说都是有用的,因为在即将到来的PostgreSQL 9.5中实现了:

CREATE OR REPLACE FUNCTION jsonb_merge(left JSONB, right JSONB)
RETURNS JSONB
AS $$
SELECT
  CASE WHEN jsonb_typeof($1) = 'object' AND jsonb_typeof($2) = 'object' THEN
       (SELECT json_object_agg(COALESCE(o.key, n.key), CASE WHEN n.key IS NOT NULL THEN n.value ELSE o.value END)::jsonb
        FROM jsonb_each($1) o
        FULL JOIN jsonb_each($2) n ON (n.key = o.key))
   ELSE 
     (CASE WHEN jsonb_typeof($1) = 'array' THEN LEFT($1::text, -1) ELSE '['||$1::text END ||', '||
      CASE WHEN jsonb_typeof($2) = 'array' THEN RIGHT($2::text, -1) ELSE $2::text||']' END)::jsonb
   END     
$$ LANGUAGE sql IMMUTABLE STRICT;
GRANT EXECUTE ON FUNCTION jsonb_merge(jsonb, jsonb) TO public;
CREATE OPERATOR || ( LEFTARG = jsonb, RIGHTARG = jsonb, PROCEDURE = jsonb_merge );

我为自己写了一个小函数,在Postgres 9.4中递归地工作。下面是函数(我希望它对你有用):

CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
    result JSONB;
    v RECORD;
BEGIN
    IF jsonb_typeof(val2) = 'null'
    THEN 
        RETURN val1;
    END IF;

    result = val1;

    FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP

        IF jsonb_typeof(val2->v.key) = 'object'
            THEN
                result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
            ELSE
                result = result || jsonb_build_object(v.key, v.value);
        END IF;
    END LOOP;

    RETURN result;
END;
$$ LANGUAGE plpgsql;

下面是使用示例:

select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
                            jsonb_update                             
---------------------------------------------------------------------
 {"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
(1 row)

正如你所看到的,它深入分析并在需要的地方更新/添加值。