PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PostgreSQL modifiant dynamiquement des champs dans un nouvel enregistrement dans une fonction de déclenchement

Il n'y a pas de solutions simples basées sur plpgsql. Quelques solutions possibles :

  1. Utilisation de hstore extension.
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 fonction basée peut être très simple :

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. Il y a quelques années, j'ai écrit une extension pl toolbox . Il existe une fonction 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)

Vous pouvez probablement trouver des solutions plpgsql uniquement basées sur des astuces avec des tables système et des tableaux comme ceci , mais je ne peux pas le suggérer. C'est trop moins lisible et pour les utilisateurs non avertis, c'est juste de la magie noire. hstore est simple et presque partout, il devrait donc être préféré.

Sur PostgreSQL 9.4 (peut-être 9.3) vous pouvez essayer de faire de la magie noire avec des manipulations 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)

Je suis donc capable d'écrire la fonction :

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 fonction basée sur JSON ne devrait pas être très rapide. hstore devrait être plus rapide.