PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm cách nào để sửa đổi các trường bên trong kiểu dữ liệu PostgreSQL JSON mới?

Cập nhật :Với PostgreSQL 9.5, có một số jsonb chức năng thao tác trong chính PostgreSQL (nhưng không có chức năng nào đối với json; phôi được yêu cầu để thao tác json giá trị).

Hợp nhất 2 (hoặc nhiều) đối tượng JSON (hoặc nối các mảng):

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

Vì vậy, thiết lập một khóa đơn giản có thể được thực hiện bằng cách sử dụng:

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

Ở đâu <key> phải là chuỗi và <value> có thể là bất kỳ loại nào to_jsonb() chấp nhận.

Để đặt giá trị sâu trong phân cấp JSON , jsonb_set() chức năng có thể được sử dụng:

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

Danh sách tham số đầy đủ của jsonb_set() :

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

path cũng có thể chứa chỉ mục mảng JSON &số nguyên âm xuất hiện ở đó tính từ cuối mảng JSON. Tuy nhiên, chỉ mục mảng JSON không tồn tại nhưng tích cực sẽ nối phần tử vào cuối mảng:

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

Để chèn vào mảng JSON (trong khi vẫn giữ nguyên tất cả các giá trị ban đầu) , jsonb_insert() chức năng có thể được sử dụng ( trong 9.6+; chỉ chức năng này, trong phần này ):

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]}]}'

Danh sách tham số đầy đủ của jsonb_insert() :

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

Một lần nữa, các số nguyên âm xuất hiện trong path đếm từ cuối mảng JSON.

Vì vậy, f.ex. thêm vào một phần cuối của một mảng JSON có thể được thực hiện với:

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

Tuy nhiên, chức năng này hoạt động hơi khác (so với jsonb_set() ) khi path trong target là khóa của đối tượng JSON. Trong trường hợp đó, nó sẽ chỉ thêm một cặp khóa-giá trị mới cho đối tượng JSON khi khóa không được sử dụng. Nếu nó được sử dụng, nó sẽ phát sinh lỗi:

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

Xóa khóa (hoặc chỉ mục) từ một đối tượng JSON (hoặc từ một mảng) có thể được thực hiện với - nhà điều hành:

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

Xóa, khỏi sâu trong phân cấp JSON có thể được thực hiện với #- nhà điều hành:

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

Đối với 9.4 , bạn có thể sử dụng phiên bản đã sửa đổi của câu trả lời gốc (bên dưới), nhưng thay vì tổng hợp một chuỗi JSON, bạn có thể tổng hợp thành một đối tượng json trực tiếp bằng json_object_agg() .

Câu trả lời ban đầu :Có thể (không có plpython hoặc plv8) trong SQL thuần túy (nhưng cần 9.3+, sẽ không hoạt động với 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

Chỉnh sửa :

Một phiên bản đặt nhiều khóa và giá trị:

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

Chỉnh sửa 2 :as @ErwinBrandstetter đã lưu ý rằng các chức năng này ở trên hoạt động giống như cái gọi là UPSERT (cập nhật một trường nếu nó tồn tại, chèn nếu nó không tồn tại). Đây là một biến thể, chỉ 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$;

Chỉnh sửa 3 :Đây là biến thể đệ quy, có thể đặt (UPSERT ) giá trị lá (và sử dụng hàm đầu tiên từ câu trả lời này), nằm tại đường dẫn khóa (nơi các khóa chỉ có thể tham chiếu đến các đối tượng bên trong, các mảng bên trong không được hỗ trợ):

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

Đã cập nhật:Đã thêm chức năng để thay thế khóa của trường json hiện có bằng một khóa nhất định khác. Có thể hữu ích cho việc cập nhật các loại dữ liệu trong quá trình di chuyển hoặc các trường hợp khác như sửa đổi cấu trúc dữ liệu.

CREATE OR REPLACE FUNCTION json_object_replace_key(
    json_value json,
    existing_key text,
    desired_key text)
  RETURNS json AS
$BODY$
SELECT COALESCE(
(
    SELECT ('{' || string_agg(to_json(key) || ':' || value, ',') || '}')
    FROM (
        SELECT *
        FROM json_each(json_value)
        WHERE key <> existing_key
        UNION ALL
        SELECT desired_key, json_value -> existing_key
    ) AS "fields"
    -- WHERE value IS NOT NULL (Actually not required as the string_agg with value's being null will "discard" that entry)

),
    '{}'
)::json
$BODY$
  LANGUAGE sql IMMUTABLE STRICT
  COST 100;

Cập nhật :các hàm hiện đã được nén lại.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách cho phép truy cập từ xa vào cơ sở dữ liệu PostgreSQL

  2. Có thể sử dụng một biến và không chỉ định kiểu trả về trong postgreSQL không?

  3. Truyền nhiều giá trị trong một tham số

  4. pg_restore Alternatives - PostgreSQL Backup và Automatic Recovery with ClusterControl

  5. Nhập .csv với cột dấu thời gian (dd.mm.yyyy hh.mm.ss) bằng psql \ copy