sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL modifierar fält dynamiskt i NY post i en triggerfunktion

Det finns inga enkla plpgsql-baserade lösningar. Några möjliga lösningar:

  1. Använda hstore förlängning.
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 baserad funktion kan vara mycket enkel:

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. För några år sedan skrev jag ett tillägg pl toolbox . Det finns en 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)

Förmodligen kan du hitta några plpgsql-lösningar baserade på några knep med systemtabeller och arrayer som detta , men jag kan inte föreslå det. Det är för mindre läsbart och för inte avancerade användare bara svart magi. hstore är enkelt och nästan överallt så det bör vara att föredra.

På PostgreSQL 9.4 (kanske 9.3) kan du prova svart magi med JSON-manipulationer:

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)

Så jag kan skriva funktion:

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-baserad funktion borde inte vara fruktansvärt snabb. hstore borde vara snabbare.



  1. Laravel 5.1 Ladda upp filer Säkerhet

  2. Ger mysql CLI-verktyget ett sätt att visa binära data på ett konsolvänligt sätt?

  3. MySQL db frågetecken istället för hebreiska tecken..?

  4. Postgres CASE-uttalande i en inlaga