PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL ändert Felder dynamisch in einem NEUEN Datensatz in einer Triggerfunktion

Es gibt keine einfachen plpgsql-basierten Lösungen. Einige mögliche Lösungen:

  1. Mit hstore Erweiterung.
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 basierte Funktion kann sehr einfach sein:

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. Vor einigen Jahren habe ich eine Erweiterung pl toolbox geschrieben . Es gibt eine Funktion 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)

Wahrscheinlich finden Sie einige plpgsql-only-Lösungen basierend auf einigen Tricks mit Systemtabellen und Arrays wie dies , aber ich kann es nicht empfehlen. Es ist zu wenig lesbar und für nicht fortgeschrittene Benutzer nur schwarze Magie. hstore ist einfach und fast überall so sollte es bevorzugt werden.

Auf PostgreSQL 9.4 (vielleicht 9.3) können Sie versuchen, mit JSON-Manipulationen schwarze Magie zu betreiben:

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)

So kann ich Funktion schreiben:

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)

JSON-basierte Funktion sollte nicht schrecklich schnell sein. hstore sollte schneller sein.