새로운 PostgreSQL JSON 데이터 유형 내에서 필드를 어떻게 수정합니까?


235

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...

답변:


331

업데이트 : PostgreSQL 9.5 에는 jsonbPostgreSQL 자체에 일부 조작 기능이 있습니다 (그러나 값 json을 조작하는 데 캐스트는 필요 하지 않습니다 json).

2 개 이상의 JSON 객체 병합 (또는 연결 배열) :

SELECT jsonb '{"a":1}' || jsonb '{"b":2}', -- will yield jsonb '{"a":1,"b":2}'
       jsonb '["a",1]' || jsonb '["b",2]'  -- will yield jsonb '["a",1,"b",2]'

따라서 간단한 키 설정 은 다음을 사용하여 수행 할 수 있습니다.

SELECT jsonb '{"a":1}' || jsonb_build_object('<key>', '<value>')

어디에서 <key>문자열이되어야하는지, <value>어떤 유형이든지 to_jsonb()받아 들일 수 있습니다 .

들어 JSON 계층 구조에서 값 깊은 설정jsonb_set()기능을 사용할 수 있습니다 :

SELECT jsonb_set('{"a":[null,{"b":[]}]}', '{a,1,b,0}', jsonb '{"c":3}')
-- will yield jsonb '{"a":[null,{"b":[{"c":3}]}]}'

의 전체 매개 변수 목록 jsonb_set():

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

pathJSON 배열 색인을 포함 할 수 있으며 JSON 배열의 끝부터 계산되는 음의 정수가 포함될 수 있습니다. 그러나 존재하지 않지만 양의 JSON 배열 인덱스는 요소를 배열 끝에 추가합니다.

SELECT jsonb_set('{"a":[null,{"b":[1,2]}]}', '{a,1,b,1000}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}'

옵션 (원래 값을 모두 유지하면서) JSON 배열로 삽입jsonb_insert()기능을 사용할 수있다 ( 9.6+에서 이러한 기능 만이 섹션 ) :

SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2')
-- will yield jsonb '{"a":[null,{"b":[2,1]}]}', and
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b,0}', jsonb '2', true)
-- will yield jsonb '{"a":[null,{"b":[1,2]}]}'

의 전체 매개 변수 목록 jsonb_insert():

jsonb_insert(target       jsonb,
             path         text[],
             new_value    jsonb,
             insert_after boolean default false)

다시 말하지만 pathJSON 배열의 끝부터 계산되는 음의 정수입니다 .

그래서 f.ex. JSON 배열의 끝에 추가는 다음과 같이 수행 할 수 있습니다.

SELECT jsonb_insert('{"a":[null,{"b":[1,2]}]}', '{a,1,b,-1}', jsonb '3', true)
-- will yield jsonb '{"a":[null,{"b":[1,2,3]}]}', and

그러나,이 기능은 약간 다르게 (이상 작동 jsonb_set())이 경우 path에는 targetJSON 개체의 핵심입니다. 이 경우 키를 사용하지 않을 때 JSON 객체에 대한 새 키-값 쌍만 추가합니다. 사용하면 오류가 발생합니다.

SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,c}', jsonb '[2]')
-- will yield jsonb '{"a":[null,{"b":[1],"c":[2]}]}', but
SELECT jsonb_insert('{"a":[null,{"b":[1]}]}', '{a,1,b}', jsonb '[2]')
-- will raise SQLSTATE 22023 (invalid_parameter_value): cannot replace existing key

JSON 객체 또는 배열에서 키 또는 인덱스를 삭제하는 것은 -연산자를 사용하여 수행 할 수 있습니다 .

SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
       jsonb '["a",1,"b",2]' - 1    -- will yield jsonb '["a","b",2]'

JSON 계층에서 깊이 삭제#-연산자를 사용하여 수행 할 수 있습니다 .

SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'

9.4 의 경우 원래 답변의 수정 된 버전 (아래)을 사용할 수 있지만 JSON 문자열을 집계하는 대신을 사용하여 json 객체로 직접 집계 할 수 있습니다 json_object_agg().

원래 답변 : 순수한 SQL에서도 가능합니다 (plpython 또는 plv8 제외) (9.3 이상 필요, 9.2에서는 작동하지 않음)

CREATE OR REPLACE FUNCTION "json_object_set_key"(
  "json"          json,
  "key_to_set"    TEXT,
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> "key_to_set"
         UNION ALL
        SELECT "key_to_set", to_json("value_to_set")) AS "fields"
$function$;

SQLFiddle

편집 :

여러 키와 값을 설정하는 버전 :

CREATE OR REPLACE FUNCTION "json_object_set_keys"(
  "json"          json,
  "keys_to_set"   TEXT[],
  "values_to_set" anyarray
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')::json
  FROM (SELECT *
          FROM json_each("json")
         WHERE "key" <> ALL ("keys_to_set")
         UNION ALL
        SELECT DISTINCT ON ("keys_to_set"["index"])
               "keys_to_set"["index"],
               CASE
                 WHEN "values_to_set"["index"] IS NULL THEN 'null'::json
                 ELSE to_json("values_to_set"["index"])
               END
          FROM generate_subscripts("keys_to_set", 1) AS "keys"("index")
          JOIN generate_subscripts("values_to_set", 1) AS "values"("index")
         USING ("index")) AS "fields"
$function$;

편집 2 : @ErwinBrandstetter가 언급했듯이 위의 기능은 소위처럼 작동 UPSERT합니다 (존재하는 경우 필드 업데이트, 존재하지 않는 경우 삽입). 변형은 다음과 같습니다 UPDATE.

CREATE OR REPLACE FUNCTION "json_object_update_key"(
  "json"          json,
  "key_to_set"    TEXT,
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_to_set") IS NULL THEN "json"
  ELSE (SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')
          FROM (SELECT *
                  FROM json_each("json")
                 WHERE "key" <> "key_to_set"
                 UNION ALL
                SELECT "key_to_set", to_json("value_to_set")) AS "fields")::json
END
$function$;

편집 3 : 여기 UPSERT에는 키 경로 (키는 내부 객체 만 참조 할 수 있으며 내부 배열은 지원되지 않음)에 위치한 리프 값을 설정 하고이 답변의 첫 번째 함수를 사용하는 재귀 변형 입니다.

CREATE OR REPLACE FUNCTION "json_object_set_path"(
  "json"          json,
  "key_path"      TEXT[],
  "value_to_set"  anyelement
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE COALESCE(array_length("key_path", 1), 0)
         WHEN 0 THEN to_json("value_to_set")
         WHEN 1 THEN "json_object_set_key"("json", "key_path"[l], "value_to_set")
         ELSE "json_object_set_key"(
           "json",
           "key_path"[l],
           "json_object_set_path"(
             COALESCE(NULLIF(("json" -> "key_path"[l])::text, 'null'), '{}')::json,
             "key_path"[l+1:u],
             "value_to_set"
           )
         )
       END
  FROM array_lower("key_path", 1) l,
       array_upper("key_path", 1) u
$function$;

업데이트 : 기능이 압축되었습니다.


5
plpgsql 함수를 시도했지만 사용 방법을 잘 모르겠습니다. select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two'); 오류 메시지를 시도 할 때 오류가 발생했습니다 ERROR: could not determine polymorphic type because input has type "unknown"
user9645

1
이것은 동등한 수행 UPSERTAN, 없다 UPDATE. 키가 json 필드에 없으면 키가 추가됩니다. 실제이 관련 질문에 봐 UPDATE: stackoverflow.com/questions/7711432/... (이것은 복합 유형이지만, 교장 JSON 비슷합니다.)
어윈 Brandstetter에게

1
사실은 @ErwinBrandstetter이지만 json에서 UPSERT는 일반적으로 업데이트와 같은 수정보다 일반적입니다 ( f.ex. sqlfiddle.com/#!15/d41d8/2897 고려 )-원래 질문을 어떻게 수정합니까? UPDATE 문을 사용하여 (json 열)? -단일 조건 외에도 이것을 UPDATE로 변환 할 수 있습니다.
pozs

1
매우 유용하고 지금 완료하십시오.
Erwin Brandstetter

1
클라이언트 (또는 사용하는 클라이언트 라이브러리)에 의존하는 @maxhud. 가능하면 명시 적 유형을 사용하십시오 (PostgreSQL은 매개 변수화 된 쿼리에서 유형을 추측 할 수 있지만 일반적으로 다형성 함수에는 적합하지 않습니다). 그러나 적어도과 같은 명시 적 캐스트를 사용할 수 있습니다 $2::text.
pozs

98

9.5에서는 jsonb_set-

UPDATE objects
SET body = jsonb_set(body, '{name}', '"Mary"', true)
WHERE id = 1; 

여기서 body는 jsonb 열 유형입니다.


안녕, 왜 그런 식으로 사용할 수 없습니다 upper: update objects set body=jsonb_set(body, '{name}', upper('"Mary"'), true) where id=1;인식하지 못하거나 어떻게 동일한 행동을 달성 할 수 있습니까? thx
Rafael Capucho

1
설정하려는 값이 "Mary"가 아닌 다른 열의 하위 문자열 인 경우 어떻게해야합니까?
앤드류

58

Postgresql 9.5에서는 다음을 수행 할 수 있습니다.

UPDATE test
SET data = data - 'a' || '{"a":5}'
WHERE data->>'b' = '2';

또는

UPDATE test
SET data = jsonb_set(data, '{a}', '5'::jsonb);

누군가 jsonb 값의 많은 필드를 한 번에 업데이트하는 방법을 물었습니다. 테이블을 생성한다고 가정 해 봅시다.

CREATE TABLE testjsonb ( id SERIAL PRIMARY KEY, object JSONB );

그런 다음 실험 행을 삽입하십시오.

INSERT INTO testjsonb
VALUES (DEFAULT, '{"a":"one", "b":"two", "c":{"c1":"see1","c2":"see2","c3":"see3"}}');

그런 다음 행을 업데이트합니다.

UPDATE testjsonb SET object = object - 'b' || '{"a":1,"d":4}';

다음은 무엇입니까?

  1. 필드를 업데이트합니다
  2. b 필드를 제거합니다
  3. d 필드 추가

데이터 선택 :

SELECT jsonb_pretty(object) FROM testjsonb;

결과는 다음과 같습니다.

      jsonb_pretty
-------------------------
 {                      +
     "a": 1,            +
     "c": {             +
         "c1": "see1",  +
         "c2": "see2",  +
         "c3": "see3",  +
     },                 +
     "d": 4             +
 }
(1 row)

내부 필드를 업데이트하려면 concat 연산자를 사용하지 마십시오 ||. 대신 jsonb_set을 사용하십시오. 간단하지 않습니다 :

UPDATE testjsonb SET object =
jsonb_set(jsonb_set(object, '{c,c1}','"seeme"'),'{c,c2}','"seehim"');

{c, c1}에 대해 concat 연산자 사용 :

UPDATE testjsonb SET object = object || '{"c":{"c1":"seedoctor"}}';

{c, c2} 및 {c, c3}을 제거합니다.

더 많은 전력을 얻으 려면 postgresql json 함수 문서 에서 전력을 찾으십시오 . #-운영자, jsonb_set기능 및 기능에 관심이있을 수 있습니다 jsonb_insert.


두 필드를 업데이트 해야하는 경우 구문은 무엇입니까?
Sunil Garg

필드 이름을 가진 json 열이있는 경우이 열에 성 필드를 추가하는 방법
Bionix1441

UPDATE users SET profile = profile || '{"lastname":"Washington"}' WHERE profile->>'name' = 'George Washington';
Fandi Susanto

9

@pozs의 답변을 바탕으로 다음은 일부 유용한 PostgreSQL 함수입니다. (PostgreSQL 9.3 이상 필요)

키로 삭제 : 키로 JSON 구조에서 값을 삭제합니다.

CREATE OR REPLACE FUNCTION "json_object_del_key"(
  "json"          json,
  "key_to_del"    TEXT
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_to_del") IS NULL THEN "json"
  ELSE (SELECT concat('{', string_agg(to_json("key") || ':' || "value", ','), '}')
          FROM (SELECT *
                  FROM json_each("json")
                 WHERE "key" <> "key_to_del"
               ) AS "fields")::json
END
$function$;

키별 재귀 삭제 : 키 경로로 JSON 구조에서 값을 삭제합니다. (@pozs json_object_set_key기능 필요 )

CREATE OR REPLACE FUNCTION "json_object_del_path"(
  "json"          json,
  "key_path"      TEXT[]
)
  RETURNS json
  LANGUAGE sql
  IMMUTABLE
  STRICT
AS $function$
SELECT CASE
  WHEN ("json" -> "key_path"[l] ) IS NULL THEN "json"
  ELSE
     CASE COALESCE(array_length("key_path", 1), 0)
         WHEN 0 THEN "json"
         WHEN 1 THEN "json_object_del_key"("json", "key_path"[l])
         ELSE "json_object_set_key"(
           "json",
           "key_path"[l],
           "json_object_del_path"(
             COALESCE(NULLIF(("json" -> "key_path"[l])::text, 'null'), '{}')::json,
             "key_path"[l+1:u]
           )
         )
       END
    END
  FROM array_lower("key_path", 1) l,
       array_upper("key_path", 1) u
$function$;

사용 예 :

s1=# SELECT json_object_del_key ('{"hello":[7,3,1],"foo":{"mofu":"fuwa", "moe":"kyun"}}',
                                 'foo'),
            json_object_del_path('{"hello":[7,3,1],"foo":{"mofu":"fuwa", "moe":"kyun"}}',
                                 '{"foo","moe"}');

 json_object_del_key |          json_object_del_path
---------------------+-----------------------------------------
 {"hello":[7,3,1]}   | {"hello":[7,3,1],"foo":{"mofu":"fuwa"}}

굉장히 유용하다! 감사합니다.
1111161171159459134

9
UPDATE test
SET data = data::jsonb - 'a' || '{"a":5}'::jsonb
WHERE data->>'b' = '2'

이것은 PostgreSQL 9.5에서 작동하는 것 같습니다


내가 이해하는 한, 이것은 데이터에서 필드 "a"를 제거한 다음 새 값으로 필드 "a"를 추가합니다. 필자의 경우 "a"의 값은 열을 기준으로합니다. 업데이트 테스트 SET 데이터 = data :: jsonb- 'a'|| ( '{ "a": "'|| myColumn || '"}') :: jsonb;
sebge2

7

필드 유형이 json 인 경우 다음이 적합합니다.

UPDATE 
table_name
SET field_name = field_name::jsonb - 'key' || '{"key":new_val}' 
WHERE field_name->>'key' = 'old_value'.

연산자 '-'는 왼쪽 피연산자에서 키 / 값 쌍 또는 문자열 요소를 삭제합니다. 키 / 값 쌍은 해당 키 값을 기준으로 일치합니다.

연산자 '||' 두 개의 jsonb 값을 새로운 jsonb 값으로 연결합니다.

이들은 jsonb 연산자이므로 다음과 같이 typecast해야합니다. : jsonb

추가 정보 : JSON 함수 및 연산자

여기 내 메모를 읽을 수 있습니다


속성 순서 재 배열이 걱정되지 않는 경우 JSON 필드를 업데이트하는 간단하고 더 나은 방법입니다.
Karthik Sivaraj

4

PostgreSQL 9.4에서는 다음과 같은 파이썬 함수를 구현했습니다. PostgreSQL 9.3에서도 작동 할 수 있습니다.

create language plpython2u;

create or replace function json_set(jdata jsonb, jpaths jsonb, jvalue jsonb) returns jsonb as $$
import json

a = json.loads(jdata)
b = json.loads(jpaths)

if a.__class__.__name__ != 'dict' and a.__class__.__name__ != 'list':
  raise plpy.Error("The json data must be an object or a string.")

if b.__class__.__name__ != 'list':
   raise plpy.Error("The json path must be an array of paths to traverse.")

c = a
for i in range(0, len(b)):
  p = b[i]
  plpy.notice('p == ' + str(p))

  if i == len(b) - 1:
    c[p] = json.loads(jvalue)

  else:
    if p.__class__.__name__ == 'unicode':
      plpy.notice("Traversing '" + p + "'")
      if c.__class__.__name__ != 'dict':
        raise plpy.Error("  The value here is not a dictionary.")
      else:
        c = c[p]

    if p.__class__.__name__ == 'int':
      plpy.notice("Traversing " + str(p))
      if c.__class__.__name__ != 'list':
        raise plpy.Error("  The value here is not a list.")
      else:
        c = c[p]

    if c is None:
      break    

return json.dumps(a)
$$ language plpython2u ;

사용법 예 :

create table jsonb_table (jsonb_column jsonb);
insert into jsonb_table values
('{"cars":["Jaguar", {"type":"Unknown","partsList":[12, 34, 56]}, "Atom"]}');

select jsonb_column->'cars'->1->'partsList'->2, jsonb_column from jsonb_table;

update jsonb_table
set jsonb_column = json_set(jsonb_column, '["cars",1,"partsList",2]', '99');

select jsonb_column->'cars'->1->'partsList'->2, jsonb_column from jsonb_table;

이전 고용주, I는 (안으로서 텍스트로 JSON 데이터를 조작하기위한 C 함수 세트를 쓴 참고 json하거나 jsonb, 예를 들어 PostgreSQL의 7, 8 및 9에 대해 타입)으로 데이터를 추출 json_path('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']')하여 데이터를 설정 json_path_set('{"obj":[12, 34, {"num":-45.67}]}', '$.obj[2]['num']', '99.87')등등. 작업에 약 3 일이 걸렸으므로 레거시 시스템에서 실행하고 여유 시간이 필요한 경우에는 노력할 가치가 있습니다. C 버전이 파이썬 버전보다 훨씬 빠르다고 생각합니다.


2

다음은이 요청을 만족시키지 않지만 (PostgreSQL 9.3에서는 json_object_agg 함수를 사용할 수 없음), 다음은 || 다가오는 PostgreSQL 9.5에서 구현 된 PostgreSQL 9.4의 연산자 :

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

2

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)

보시다시피 깊이 분석하고 필요한 경우 값을 업데이트 / 추가하십시오.


2

이것은 문자열 유형 필드를 업데이트하려고 할 때 효과적이었습니다.

UPDATE table_name 
SET body = jsonb_set(body, '{some_key}', to_json('value'::TEXT)::jsonb);

그것이 다른 누군가를 돕기를 바랍니다!

table_name 테이블에 body라는 jsonb 열이 있고 body.some_key = 'value'를 변경한다고 가정합니다.


불행히도 이것은 JSON 특정 함수를 통한 조작과 같은 방식으로 JSON을 다시 포맷합니다
Lu55

1

슬프게도, 나는 문서에서 아무것도 찾지 못했지만 몇 가지 해결 방법을 사용할 수 있습니다. 예를 들어 확장 기능을 작성할 수 있습니다.

예를 들어, 파이썬에서 :

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

Amazon RDS가 plpython3u를 지원하지 않는 것은 수치입니다!
dbau

2
value또한 필요합니다 loads문자열 (같은 숫자가 아닌 값을 설정할 때 js[key] = loads(value)) - 그렇지 않으면 :select json_update('{"a":"a"}', 'a', to_json('b')); -> {"a": "\"b\""}
hooblei

값이 None으로 설정된 경우 키 삭제를 포함하도록이 답변을 수정할 수도 있습니다.`값이 None 인 경우 : del data [key]
Joshua Burns

1

다음 plpython 스 니펫이 유용 할 수 있습니다.

CREATE EXTENSION IF NOT EXISTS plpythonu;
CREATE LANGUAGE plpythonu;

CREATE OR REPLACE FUNCTION json_update(data json, key text, value text)
 RETURNS json
 AS $$
    import json
    json_data = json.loads(data)
    json_data[key] = value
    return json.dumps(json_data, indent=4)
 $$ LANGUAGE plpythonu;

-- Check how JSON looks before updating

SELECT json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
FROM sc_server_centre_document WHERE record_id = 35 AND template = 'CFRDiagnosis';

-- Once satisfied update JSON inplace

UPDATE sc_server_centre_document SET content = json_update(content::json, 'CFRDiagnosis.mod_nbs', '1')
WHERE record_id = 35 AND template = 'CFRDiagnosis';

1

이전 답변이 숙련 된 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 () 함수를 사용하여 키에 새로운 값을 할당합니다

jsonb_set ()에 대한 매개 변수

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

" target "에서-jsonb column-name을 배치합니다 (이것은 수정중인 테이블 열입니다)

" path "-우리가 덮어 쓰려는 키로 이어지는 "json 키 경로"입니다.

" new_value "-이것이 우리가 할당 한 새로운 값입니다

이 경우 key1 (key1-> key13) 아래에있는 key13 값을 업데이트하려고합니다.

따라서 경로 구문 은 '{key1, key13}'입니다. 경로는 가장 까다로운 부분이었습니다.

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

0

다음 jsonb과 같이 키를 원자 적으로 증가시킬 수도 있습니다 .

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}

정의되지 않은 키->는 시작 값 0을 가정합니다.

자세한 설명은 https://stackoverflow.com/a/39076637에서 내 대답을 참조하십시오.


0

을 사용하는 사람들을 위해 mybatis다음은 업데이트 명령문의 예입니다.

<update id="saveAnswer">
    update quiz_execution set answer_data = jsonb_set(answer_data, concat('{', #{qid}, '}')::text[], #{value}::jsonb), updated_at = #{updatedAt}
    where id = #{id}
</update>


매개 변수 :

  • qid필드의 키입니다.
  • value, 필드 값에 유효한 JSON 문자열입니다 (
    예 :을 통해 객체에서 json 문자열로 변환) jackson.

0

예를 들어 내 문자열은 { "a1": { "a11": "x", "a22": "y", "a33": "z"}}와 같습니다.

임시 테이블을 사용하여 json을 업데이트합니다.이 테이블은 다소 적은 양의 데이터 (<1.000.000)에 충분합니다. 나는 다른 길을 찾았지만 휴가를 갔다가 잊었다.

그래서. 쿼리는 다음과 같습니다.

with temp_table as (
select 
a.id,
a->'a1'->>'a11' as 'a11',
a->'a1'->>'a22' as 'a22',
a->'a1'->>'a33' as 'a33',
u1.a11updated
from foo a
join table_with_updates u1 on u1.id = a.id)
    update foo a
    set a = ('{"a1": {"a11": "'|| t.a11updated ||'",
        "a22":"'|| t.a22 ||'",
        "a33":"'|| t.a33 ||'"}}')::jsonb
    from temp_table t
    where t.id = a.id;

json보다 string과 관련이 있지만 작동합니다. 기본적으로 모든 데이터를 임시 테이블로 가져 와서 백업 한 데이터로 연결 구멍을 연결하는 동안 문자열을 만들고 jsonb로 변환합니다.

Json_set이 더 효율적일 수 있지만 여전히 중단됩니다. 처음으로 사용하려고했을 때 문자열을 완전히 엉망으로 만들었습니다.


1
안녕하세요, StackOverflow에 오신 것을 환영합니다! 이 질문에 이미 허용 된 답변이 있습니다.
hongsy

-2

from python pycopg2또는 or 와 같은 프로그래밍 언어 클라이언트를 사용하여이 쿼리를 작성하는 경우 먼저 Node Postgres새 데이터를 JSON으로 구문 분석하십시오.

파이썬 사전은 JSON 객체와 동일하지만 쉽게 사전에 json.dumps를 수행하지 않는 것처럼 보일 수 있습니다.

간단한 파이썬 스 니펫 :

def change_destination(self,parcel_id,destlatlng): query="UPDATE parcels SET destlatlng = '{}' WHERE parcel_id ={};".format(json.dumps(destlatlng), parcel_id) self.cursor.execute(query2) self.connection.commit()

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.