【问题标题】:Create Trigger For Update another row automatically on same table using postgresql使用 postgresql 在同一个表上创建自动更新另一行的触发器
【发布时间】:2020-02-27 13:06:54
【问题描述】:

我想创建一个触发器,它可以更新 PostgreSQL 上同一张表上的另一行。

如果我像这样运行查询:

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

我预期的这些结果。

说明:

我想在id:2的行上设置字段amount,其中amount的值来自子查询的查询结果,所以id:2上的金额值与id:1相同

希望通过这个创建的触发器,我可以更新id=1 上的amount 值,因此id:2 上的amount 值与id:1 相同

更新结果前:

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

当我将 id:1 上的 amount 值更新为 100 时,id:2 上的 amount 值变为 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 更新金额后,金额会自动更新

使用我编写的 UDF 解决问题的示例:

  1. 我将id:1的数量更新为2000。id:2的数量没有更新为2000
  2. 当我运行查询时选择 update_amount(1,2);
  3. id:2 的数量与 id:1 的数量相同

我需要一个 PostgreSQL 上的触发器来自动化或替换我编写的 UDF 的功能

【问题讨论】:

  • 你在哪一部分有困难?
  • 感谢您的评论,我很难将我写的 UDF 转换为触发器,因此我可以替换我的临时解决方案。问候
  • 要更新的行是刚刚插入的行还是其他行?
  • 嗨,我总是更新的行是 id 1,当我更新 id 1 上的金额值时,id 2 上的金额值反映了更新后的金额值 id 1
  • 一般情况总是在更新 id N 时想要 id N+1 的情况吗? “update tokens set amount = 10 where id = 3;”会发生什么?甚至“更新令牌设置数量 = 50 其中 id = 2;”?

标签: postgresql triggers user-defined-functions


【解决方案1】:

你想做什么并不难,我会告诉你的。但首先:这是一个非常非常糟糕的想法。事实上,一些数据库,最著名的 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 触发器:trigger function 和触发器。请注意,该函数必须在调用它的触发器之前定义。

-- 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; 

然而,触发器中的硬编码 id 并不是很有用,毕竟“更新 ... 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,我可以从 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;     

【讨论】:

    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    相关资源
    最近更新 更多