Không có giải pháp dựa trên plpgsql đơn giản. Một số giải pháp khả thi:
- Sử dụng
hstore
phần mở rộng.
CREATE TYPE footype AS (a int, b int, c int); postgres=# select row(10,20,30); row ------------ (10,20,30) (1 row) postgres=# select row(10,20,30)::footype #= 'b=>100'; ?column? ------------- (10,100,30) (1 row)
hstore
hàm dựa có thể rất đơn giản:
create or replace function update_fields(r anyelement, variadic changes text[]) returns anyelement as $$ select $1 #= hstore($2); $$ language sql; postgres=# select * from update_fields(row(10,20,30)::footype, 'b', '1000', 'c', '800'); a | b | c ----+------+----- 10 | 1000 | 800 (1 row)
- Vài năm trước, tôi đã viết một tiện ích mở rộng hộp công cụ pl
. Có một hàm
record_set_fields
:
pavel=# select * from pst.record_expand(pst.record_set_fields(row(10,20),'f1',33)); name | value | typ ------+-------+--------- f1 | 33 | integer f2 | 20 | integer (2 rows)
Có thể bạn có thể tìm thấy một số giải pháp chỉ plpgsql dựa trên một số thủ thuật với các bảng và mảng hệ thống như cái này
, nhưng tôi không thể đề xuất nó. Nó quá khó đọc và đối với những người dùng không chuyên sâu thì chỉ có ma thuật đen. hstore
rất đơn giản và hầu như ở mọi nơi, vì vậy nó nên được ưu tiên hơn.
Trên PostgreSQL 9.4 (có thể là 9.3), bạn có thể thử sử dụng phép thuật đen với các thao tác JSON:
postgres=# select json_populate_record(NULL::footype, jo) from (select json_object(array_agg(key), array_agg(case key when 'b' then 1000::text else value end)) jo from json_each_text(row_to_json(row(10,20,30)::footype))) x; json_populate_record ---------------------- (10,1000,30) (1 row)
Vì vậy, tôi có thể viết hàm:
CREATE OR REPLACE FUNCTION public.update_field(r anyelement, fn text, val text, OUT result anyelement) RETURNS anyelement LANGUAGE plpgsql AS $function$ declare jo json; begin jo := (select json_object(array_agg(key), array_agg(case key when 'b' then val else value end)) from json_each_text(row_to_json(r))); result := json_populate_record(r, jo); end; $function$ postgres=# select * from update_field(row(10,20,30)::footype, 'b', '1000'); a | b | c ----+------+---- 10 | 1000 | 30 (1 row)
Chức năng dựa trên JSON không được nhanh khủng khiếp. hstore
sẽ nhanh hơn.