PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

PostgreSQL che modifica i campi in modo dinamico nel NUOVO record in una funzione di trigger

Non ci sono semplici soluzioni basate su plpgsql. Alcune possibili soluzioni:

  1. Utilizzo di hstore estensione.
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 la funzione basata può essere molto semplice:

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)
  1. Alcuni anni fa ho scritto un'estensione pl toolbox . C'è una funzione 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)

Probabilmente puoi trovare alcune soluzioni solo plpgsql basate su alcuni trucchi con tabelle e array di sistema come questo , ma non posso suggerirlo. È troppo meno leggibile e per utenti non esperti solo magia nera. hstore è semplice e quasi ovunque, quindi dovrebbe essere il modo preferito.

Su PostgreSQL 9.4 (forse 9.3) puoi provare la magia nera con manipolazioni 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)

Quindi sono in grado di scrivere la funzione:

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)

La funzione basata su JSON non dovrebbe essere terribilmente veloce. hstore dovrebbe essere più veloce.