Cập nhật : Với PostgreQuery 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 json
được yêu cầu để thao tác json
các giá trị).
Hợp nhất 2 (hoặc nhiều hơn) các đố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 phím đơ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>')
Trường hợp <key>
nên là chuỗi, và <value>
có thể là bất cứ loại nào to_jsonb()
chấp nhận.
Để đặt giá trị sâu trong cấu trúc phân cấp JSON , jsonb_set()
có thể sử dụng hàm:
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 các chỉ mục mảng JSON và các số nguyên âm xuất hiện ở đó được tính từ cuối các mảng JSON. Tuy nhiên, một 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 bảo toàn tất cả các giá trị ban đầu) , jsonb_insert()
có thể sử dụng hàm ( 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 path
đếm từ cuối mảng JSON.
Vì vậy, f.ex. nối thêm vào 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, hàm này hoạt động hơi khác (so với jsonb_set()
) khi khóa path
trong target
là một đố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 một khóa (hoặc một chỉ mục) khỏi một đối tượng JSON (hoặc, từ một mảng) có thể được thực hiện với -
toán tử:
SELECT jsonb '{"a":1,"b":2}' - 'a', -- will yield jsonb '{"b":2}'
jsonb '["a",1,"b",2]' - 1 -- will yield jsonb '["a","b",2]'
Việc xóa, từ sâu trong hệ thống phân cấp JSON có thể được thực hiện với #-
toán tử:
SELECT '{"a":[null,{"b":[3.14]}]}' #- '{a,1,b,0}'
-- will yield jsonb '{"a":[null,{"b":[]}]}'
Trong phiên bản 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 chuỗi JSON, bạn có thể tổng hợp thành một đối tượng json trực tiếp json_object_agg()
.
Câu trả lời gốc : Cũng 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 & 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 : như @ErwinBrandstetter lưu ý các chức năng trên ở 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 ở đường dẫn khóa (trong đó các khóa chỉ có thể tham chiếu đến các đối tượng bên trong, 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 : các chức năng được nén ngay bây giờ.
select json_object_set_key((select data from test where data->>'b' = '2'), 'b', 'two');
thông báo lỗi làERROR: could not determine polymorphic type because input has type "unknown"