我有两张桌子
batch (batch_id,start_date,end_date,batch_strength,is_locked)
sem (user_id,is_active,no_of_days)
我已执行下面给出的触发程序,然后使用查询
更新表格CREATE OR REPLACE FUNCTION em_batch_update()
RETURNS trigger AS $em_sem_batch$
BEGIN
UPDATE batch set is_locked='TRUE'
where (start_date
+ (select no_of_days from sem
WHERE is_active='TRUE' and user_id='OSEM')
) <= current_date;
return NEW;
END;
$em_sem_batch$ LANGUAGE plpgsql;
CREATE TRIGGER em_sem_batch
BEFORE UPDATE ON batch FOR EACH ROW EXECUTE PROCEDURE em_batch_update();
update em_batch set batch_strength=20 where batch_id='OD001C001B3';
发生错误:
错误:超出堆栈深度限制
提示:增加配置参数“max_stack_depth”(目前为2048kB), 确保平台的堆栈深度限制足够后。
答案 0 :(得分:6)
有几种方法可以阻止你内置到触发器中的无限递归,最优雅和高效的可能是在你的触发器中为WHERE
语句添加UPDATE
子句功能:
CREATE OR REPLACE FUNCTION em_batch_update()
RETURNS trigger AS
$func$
BEGIN
UPDATE batch b
SET is_locked = TRUE
FROM sem s
WHERE s.is_active
AND s.user_id = 'OSEM'
AND b.start_date <= (current_date - s.no_of_days)
AND b.is_locked IS DISTINCT FROM TRUE; -- prevent infinite recursion!
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER em_sem_batch
BEFORE UPDATE ON batch
FOR EACH STATEMENT
EXECUTE PROCEDURE em_batch_update();
我改变了一些其他的东西以走向理智:
由于触发器功能对每一行执行相同操作,因此我将其更改为可能多更便宜statement-level trigger。
因此,我制作了触发器功能RETURN NULL
,因为,I quote the manual here:
每个语句触发器调用的触发器函数应始终使用 返回NULL。
batch.is_locked
和sem.is_active
看起来像布尔列。为他们使用适当的boolean
data type。我的代码正在构建它。
我还完全重写了您的UPDATE
查询。特别是batch.start_date
上的条件,以便在可用时使用索引。
如果定义batch.is_locked
NOT NULL
,则WHERE
条件可简化为:
AND b.is_locked = FALSE;
答案 1 :(得分:4)
您的UPDATE
触发器在同一个表上运行另一个UPDATE
,这将再次触发该触发器,因此您将获得无限递归。你可能需要稍微重新设计一下,但如果不解释你想要做什么,就很难说。
答案 2 :(得分:0)
在这种情况下无限递归,因为更新触发器将对表batch
执行更新操作,并且在em_sem_batch
触发器内部执行update语句之后将触发相同的操作。为了防止这在表中添加一列,在更新语句的触发器更新中,该列也对某些值进行了添加,并添加if条件以检查该列是否具有该常量值,如果是,则避免执行update语句,否则执行update语句。
见下面的例子:
CREATE FUNCTION public.trigger_fuction()
RETURNS trigger
LANGUAGE 'plpgsql'
NOT LEAKPROOF
AS $BODY$
BEGIN
IF NEW.data_replicated=true THEN
UPDATE sample SET data_replicated=false WHERE id=NEW.id;
raise notice 'changed data replicated of sample with id as %',NEW.ID;
END IF;
RETURN NEW;
END;
$BODY$;
CREATE TRIGGER data_replication_trigger
AFTER UPDATE
ON sample
FOR EACH ROW
EXECUTE PROCEDURE trigger_fuction();
在此示例中,示例表具有data_replicated布尔字段,该字段将在执行触发器时更新。