Создать триггер для автоматического обновления другой строки в той же таблице с помощью postgresql - PullRequest
0 голосов
/ 01 ноября 2019

Я хочу создать триггер, который может обновить другую строку в той же таблице на PostgreSQL.

, если я выполню запрос следующим образом:

UPDATE tokens
SET amount = (SELECT amount FROM tokens WHERE id = 1)
where id = 2

эти результаты, которые я ожидал.

описание:

я хочу установить поле amount в строке с id:2, где значение amount соответствует результату запроса в подзапросе, поэтому значение количества в id:2 совпадает с id:1

Надеюсь, с помощью этого созданного триггера я смогу обновить amount значение на id=1, поэтому значение amount на id:2 совпадает с id:1

Перед результатом обновления:

id | amount|
1  | 200   |
2  | 200   |

Когда я обновляю значение amount с id:1 до 100, поэтому значение amount на id:2 становится 100

После обновления:

id | amount|
1  | 100   | 
2  | 100   |  

Обновление для моего временного решения: я просто создаю UDF, как это

CREATE FUNCTION update_amount(id_ops integer, id_mir integer) returns boolean LANGUAGE plpgsql AS $$
BEGIN
 UPDATE tokens SET amount = (SELECT amount FROM tokens WHERE id = id_ops) WHERE id = id_mir;
 RETURN 1;
END;
$$;

описание:

  1. id_ops:id, где сумма, которую я всегда обновляю
  2. id_mir: id, где сумма автоматически обновляется после того, как я обновляю сумму с id_ops

EПример использования моего написанного UDF для решения моей проблемы:

  1. Я обновляю количество идентификаторов: 1 до 2000. Количество идентификаторов: 2 не обновляется до 2000
  2. Когда я запускаюquery select update_amount (1,2);
  3. Количество идентификатора: 2 будет одинаковым с количеством идентификатора: 1

Мне нужен триггер на PostgreSQL для автоматизации или замены функцииUDF, что я написал

1 Ответ

0 голосов
/ 02 ноября 2019

То, что вы хотите сделать, не так уж сложно, я вам покажу. Но сначала: это очень очень плохая идея. На самом деле достаточно плохо, что некоторые базы данных, в частности Oracle, выдают исключение, если пытаются. К сожалению, Postgres позволяет это. По сути, вы создаете рекурсивное обновление при обновлении таблицы, которая инициировала триггер. Это обновление, в свою очередь, запускает триггер. Без логики, чтобы остановить эту рекурсию, вы можете обновить каждую строку в таблице. Я предполагаю, что это выдержка для гораздо большего требования, или, возможно, вы просто хотите знать, как создать триггер. Итак, мы начинаем:

-- setup
drop table if exists tokens;
create table tokens( id integer, amount numeric(6,2));
-- create initial test data
insert into tokens(id, amount)
  values (1,100), (2,150.69), (3,95.50), (4,75), (5,16.40);

Теперь сердечный триггер Postgres: функция запуска и триггер. Обратите внимание, что функция должна быть определена до триггера, который ее вызывает.

-- create a trigger function: That is a function returning trigger.
create or replace function tokens_bur_func()
returns trigger
language plpgsql
as $$
begin 
    if new.id = 1
    then
        update tokens
           set amount = new.amount
         where id = 2;
    end if;
    return new;
end ;
$$;

-- create the trigger
create trigger tokens_bur
    before update of amount 
    on tokens
    for each row execute procedure tokens_bur_func();

--- test 
select *
  from tokens
 order by id; 

-- do an initial update
update tokens
   set amount = 200
 where id = 1;
-- Query returned successfully: one row affected, 31 msec execution time. 
-- 1 row? Yes:  DML count does not see change made from within trigger.
-- but
select *
  from tokens
 order by id; 

Жесткие идентификаторы кодирования в триггере, однако, не очень функциональны, поскольку «update ... where id in (1,2)» будет намного проще и безопаснее, поскольку не требует рекурсииостанови логику. Итак, чуть более общая триггерная функция:

-- More general but still vastly limited:
-- trigger that mirrors subsequent row whenever an odd id is updated.
create or replace function tokens_bur_func()
returns trigger
language plpgsql
as $$
begin 
    if mod(new.id, 2)=1
    then 
        update tokens
           set amount = new.amount
         where id = new.id+1;
    end if;
    return new;
end ;
$$; 

-- test
update tokens
   set amount = 900
 where id = 3; 

update tokens
   set amount = 18.95
 where id in (2,5);

select *
  from tokens
 order by id;

Независимо от того, как вы поступите, вам потребовалось предварительное знание специфики обновления. Например, вы сказали, что «это может быть id 2, для этого я могу установить mirror from id 3», поэтому вам потребуется каким-либо образом изменить базу данных, либо изменив функцию триггера, либо триггер для передачи параметров. (Триггеры могут передавать параметры, но они являются статическими, предоставленными во время создания триггера). Наконец, убедитесь, что вы поняли логику остановки рекурсии. Потому что если нет:

-- The Danger: What happens WITHOUT the 'stopper condition'
-- Using an almost direct conversion of your UDT
-- using new_id as  
create or replace function tokens_bur_func()
returns trigger
language plpgsql
as $$
begin 
    update tokens
       set amount = new.amount
     where id = new.id+1;
    return new;
end ;
$$;  

-- test
update tokens
   set amount = 137.92
 where id = 1; 
-- Query returned successfully: one row affected, 31 msec execution time. 
-- but 
select *
  from tokens
 order by id;     
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...