为使用postgresql自动更新同一表上的另一行创建触发器
我想创建一个触发器,它可以在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
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;”?