Tidak ada solusi sederhana berbasis plpgsql. Beberapa solusi yang mungkin:
- Menggunakan
hstore
ekstensi.
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
fungsi berbasis bisa sangat sederhana:
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)
- Beberapa tahun yang lalu saya menulis ekstensi pl kotak alat
. Ada fungsi
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)
Mungkin Anda dapat menemukan beberapa solusi hanya plpgsql berdasarkan beberapa trik dengan tabel dan array sistem seperti ini
, tapi saya tidak bisa menyarankannya. Itu terlalu kurang dapat dibaca dan untuk pengguna yang tidak mahir hanya ilmu hitam saja. hstore
sederhana dan hampir di mana-mana sehingga harus menjadi cara yang disukai.
Di PostgreSQL 9.4 (mungkin 9.3) Anda dapat mencoba sihir hitam dengan manipulasi 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)
Jadi saya bisa menulis fungsi:
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)
Fungsi berbasis JSON seharusnya tidak terlalu cepat. hstore
harus lebih cepat.