如何在不达到 max_stack_depth 的情况下更新与 plpgsql 中 insert/update 相同的行
How to update same line than insert/update in plpgsql without reaching max_stack_depth
我的问题是我达到了堆栈的极限。消息错误显示“您应该增加 max_stack_depth
”,并显示我用来更新另一列的行。
我在更新请求(下面的代码)后遇到此错误。
我知道我的问题可能看起来像其他问题,但其中 none 解释了为什么我会遇到此错误。
我想做的事情很简单,我已经做了很多次了,但是这里我遗漏了一些东西。
我想:如果 table support_fh
上有更新,请触发。我希望此触发器执行以下操作:
如果更新请求的新值是 section
= 'DISTRIBUTION'
and modulo
= '6'
and fabricant
= 'NEXANS'
and capacite
= 12
然后设置 diametre
= '12.5'
(下面的代码)。
当然是diametre
的行,跟更新请求在同一行。
此外,我知道我应该使用 character varying
类型而不是 integer
类型,但我被要求那样做。
我的触发函数:
create or replace function maj_diam() returns trigger
as
$$
Declare fab_loc character varying;
Declare section_loc character varying;
Declare capa_loc character varying;
Declare modulo_loc character varying;
BEGIN
Select fabricant into fab_loc from support_fh where id = new.id;
Select section into section_loc from support_fh where id = new.id;
Select capcite into capa_loc from support_fh where id = new.id;
Select modulo into modulo_loc from support_fh where id = new.id;
if fab_loc = 'NEXANS' and section_loc = 'DISTRIBUTION'
and capa_loc = '12' and modulo_loc = '6' then
update support_fh set diametre = '12.2' where id = new.id;
endif;
return new;
end;
$$;
我的触发器:
create trigger maj_diam
After update on support_fh
for each row
execute procedure maj_diam();
我测试触发器的更新请求:
update support_fh set fabricant = 'NEXANS', section = 'DISTRIBUTION', capacite = '12', modulo = '6'
where id = 11827;
我想从中吸取教训,所以,如果可能的话,请向我解释我在这里做错了什么,或者我的方法是否缺乏洞察力。
您遇到这个问题是因为触发器中的更新会再次启动触发器,从而导致无限循环。 max_stack_depth
的值都不够大(无论如何增加该值太多都是危险的)。
您应该创建一个 BEFORE
触发器并修改即将插入的 NEW
值,而不是您正在做的事情:
IF NEW.fab_loc = 'NEXANS' AND NEW.section_loc = 'DISTRIBUTION'
AND NEW.capa_loc = '12' AND NEW.modulo_loc = '6'
THEN
NEW.diametre := '12.2';
END IF;
如果要更改更新(或插入)行中的列,请不要在触发器函数中使用 UPDATE
。将触发器声明为 BEFORE UPDATE
,然后简单地分配新值。
您也不需要四个 select 语句来读取同一 table 中的四列。
但是由于您只访问已更新的同一行中的列,您甚至根本不需要 SELECT。
所以你的触发函数可以简化为:
create or replace function maj_diam() returns trigger
as
$$
BEGIN
if new.fabricant = 'NEXANS'
and new.section = 'DISTRIBUTION'
and new.capcite = '12'
and new.modulo = '6'
then
new.diametre := '12.2';
end if;
return new;
end;
$$;
假设 capcite、modulo 和 diametre 实际上是数字,您不应该将它们与 varchar 值进行比较。所以上面的代码大概应该是:new.diametre := 12.2;
或者 new.capcite = 12
.
触发器定义需要修改为:
create trigger maj_diam
BEFORE update on support_fh
for each row
execute procedure maj_diam();
我的问题是我达到了堆栈的极限。消息错误显示“您应该增加 max_stack_depth
”,并显示我用来更新另一列的行。
我在更新请求(下面的代码)后遇到此错误。
我知道我的问题可能看起来像其他问题,但其中 none 解释了为什么我会遇到此错误。
我想做的事情很简单,我已经做了很多次了,但是这里我遗漏了一些东西。
我想:如果 table support_fh
上有更新,请触发。我希望此触发器执行以下操作:
如果更新请求的新值是 section
= 'DISTRIBUTION'
and modulo
= '6'
and fabricant
= 'NEXANS'
and capacite
= 12
然后设置 diametre
= '12.5'
(下面的代码)。
当然是diametre
的行,跟更新请求在同一行。
此外,我知道我应该使用 character varying
类型而不是 integer
类型,但我被要求那样做。
我的触发函数:
create or replace function maj_diam() returns trigger
as
$$
Declare fab_loc character varying;
Declare section_loc character varying;
Declare capa_loc character varying;
Declare modulo_loc character varying;
BEGIN
Select fabricant into fab_loc from support_fh where id = new.id;
Select section into section_loc from support_fh where id = new.id;
Select capcite into capa_loc from support_fh where id = new.id;
Select modulo into modulo_loc from support_fh where id = new.id;
if fab_loc = 'NEXANS' and section_loc = 'DISTRIBUTION'
and capa_loc = '12' and modulo_loc = '6' then
update support_fh set diametre = '12.2' where id = new.id;
endif;
return new;
end;
$$;
我的触发器:
create trigger maj_diam
After update on support_fh
for each row
execute procedure maj_diam();
我测试触发器的更新请求:
update support_fh set fabricant = 'NEXANS', section = 'DISTRIBUTION', capacite = '12', modulo = '6'
where id = 11827;
我想从中吸取教训,所以,如果可能的话,请向我解释我在这里做错了什么,或者我的方法是否缺乏洞察力。
您遇到这个问题是因为触发器中的更新会再次启动触发器,从而导致无限循环。 max_stack_depth
的值都不够大(无论如何增加该值太多都是危险的)。
您应该创建一个 BEFORE
触发器并修改即将插入的 NEW
值,而不是您正在做的事情:
IF NEW.fab_loc = 'NEXANS' AND NEW.section_loc = 'DISTRIBUTION'
AND NEW.capa_loc = '12' AND NEW.modulo_loc = '6'
THEN
NEW.diametre := '12.2';
END IF;
如果要更改更新(或插入)行中的列,请不要在触发器函数中使用 UPDATE
。将触发器声明为 BEFORE UPDATE
,然后简单地分配新值。
您也不需要四个 select 语句来读取同一 table 中的四列。
但是由于您只访问已更新的同一行中的列,您甚至根本不需要 SELECT。
所以你的触发函数可以简化为:
create or replace function maj_diam() returns trigger
as
$$
BEGIN
if new.fabricant = 'NEXANS'
and new.section = 'DISTRIBUTION'
and new.capcite = '12'
and new.modulo = '6'
then
new.diametre := '12.2';
end if;
return new;
end;
$$;
假设 capcite、modulo 和 diametre 实际上是数字,您不应该将它们与 varchar 值进行比较。所以上面的代码大概应该是:new.diametre := 12.2;
或者 new.capcite = 12
.
触发器定义需要修改为:
create trigger maj_diam
BEFORE update on support_fh
for each row
execute procedure maj_diam();