为使用postgresql自动更新同一表上的另一行创建触发器

为使用postgresql自动更新同一表上的另一行创建触发器,postgresql,triggers,user-defined-functions,Postgresql,Triggers,User Defined Functions,我想创建一个触发器,它可以在PostgreSQL上更新同一表上的另一行 如果我像这样运行查询: UPDATE tokens SET amount = (SELECT amount FROM tokens WHERE id = 1) where id = 2 这些结果是我所期望的 说明: 我想在id为2的行上设置字段amount,其中amount值来自子查询的查询结果,因此id:2上的amount值与id:1相同 希望通过这个创建的触发器,我可以更新id=1上的amount值,这样id:2上的a

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

如果我像这样运行查询:

UPDATE tokens
SET amount = (SELECT amount FROM tokens WHERE id = 1)
where id = 2
这些结果是我所期望的

说明:

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

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

更新结果之前:

id | amount|
1  | 200   |
2  | 200   |
id | amount|
1  | 100   | 
2  | 100   |  
当我将
id:1上的
amount
值更新为100时,
id:2上的
amount
值变为100

更新结果后:

id | amount|
1  | 200   |
2  | 200   |
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;
$$;
说明:

  • id_ops:id我经常更新的金额
  • id\u mir:id,在我使用id\u ops更新金额后,金额会自动更新
  • 使用我编写的UDF解决问题的示例:

  • 我将id:1的数量更新为2000。id:2的数量未更新为2000
  • 当我运行查询时,选择更新金额(1,2)
  • id:2的金额将与id:1上的金额相同

  • 我需要PostgreSQL上的触发器来自动执行或替换我编写的UDF函数

    您想做什么?我会告诉您,其实并不难。但首先:这是一个非常糟糕的想法。事实上,这已经够糟糕的了,一些数据库(最著名的Oracle)在尝试时会抛出异常。不幸的是,博士后允许这样做。在更新启动触发器的表时,基本上创建一个递归更新。此更新将依次启动触发器。如果没有停止此递归的逻辑,您可以更新表中的每一行
    我假设这是一个更大需求的摘录,或者您只是想知道如何创建触发器。因此,我们开始:

    -- 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);
    
    现在心脏后遗症的触发因素:心脏,和触发因素。注意:函数必须在调用它的触发器之前定义

    -- 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并不是很有效,毕竟“更新…其中id在(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;
    
    无论您如何进行,您都需要事先了解更新细节。例如,您说“可能是ID2,我可以从ID3设置镜像”,要这样做,您需要以某种方式更改数据库,要么更改触发器函数,要么更改触发器以传递参数。(触发器可以传递参数,但它们是静态的,在创建触发器时提供)
    最后,请确保您的递归停止逻辑已停止。因为如果不是:

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

    你想做什么其实没那么难,我来告诉你。但首先:这是一个非常糟糕的想法。事实上,这已经够糟糕的了,一些数据库(最著名的Oracle)在尝试时会抛出异常。不幸的是,博士后允许这样做。在更新启动触发器的表时,基本上创建一个递归更新。此更新将依次启动触发器。如果没有停止此递归的逻辑,您可以更新表中的每一行
    我假设这是一个更大需求的摘录,或者您只是想知道如何创建触发器。因此,我们开始:

    -- 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);
    
    现在心脏后遗症的触发因素:心脏,和触发因素。注意:函数必须在调用它的触发器之前定义

    -- 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并不是很有效,毕竟“更新…其中id在(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;
    
    无论您如何进行,您都需要事先了解更新细节。例如,您说“可能是ID2,我可以从ID3设置镜像”,要这样做,您需要以某种方式更改数据库,要么更改触发器函数,要么更改触发器以传递参数。(触发器可以传递参数,但它们是静态的,在创建触发器时提供)
    最后,请确保您的递归停止逻辑已停止。因为如果不是:

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

    您对哪一部分有困难?谢谢您的评论,我很难将我编写的UDF转换为触发器,因此我可以替换我的临时解决方案。是否重新指定要更新刚插入的行或其他行?您好,我始终更新的行是id 1,当我更新id 1上的金额值时,id 2上的金额值与更新的金额值id 1镜像是一般条件?更新id N时,是否始终希望id N+1?“更新令牌设置金额=10,其中id=3;”会发生什么情况?或者甚至是“更新令牌设置金额=50,其中id=2;”?您对哪一部分有困难?谢谢您的评论,我很难将我编写的UDF转换为触发器,因此我可以替换我的临时解决方案。是否重新指定要更新刚插入的行或其他行?您好,我始终更新的行是id 1,当我更新id 1上的金额值时,id 2上的金额值与更新的金额值id 1镜像是一般条件?更新id N时,是否始终希望id N+1?“更新令牌设置金额=10,其中id=3;”会发生什么情况?甚至“更新令牌设置金额=50,其中id=2;”?