PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL динамично модифициране на полета в НОВ запис в тригерна функция

Няма прости решения, базирани на plpgsql. Някои възможни решения:

  1. Използване на hstore разширение.
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 базираната функция може да бъде много проста:

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. Преди няколко години написах разширение pl toolbox . Има функция 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)

Вероятно можете да намерите някои решения само за plpgsql, базирани на някои трикове със системни таблици и масиви като това , но не мога да го предложа. Той е твърде по-малко четлив и за ненапреднал потребител е само черна магия. hstore е прост и почти навсякъде, така че трябва да бъде предпочитан начин.

На PostgreSQL 9.4 (може би 9.3) можете да опитате черна магия с 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)

Така че мога да напиша функция:

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 функция не трябва да е ужасно бърза. hstore трябва да е по-бързо.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL срещу PostgreSQL за уеб приложения

  2. Не може да се извади офсетно-наивно и офсетно-известно време за дати

  3. Премахване на елемент от масив в обект JSONB

  4. Има ли хеш функция в PostgreSQL?

  5. Направете emacs да подчертава синтаксиса на postgresql по подразбиране