如何使用更新触发器获取主 table 中的详细信息总和 table 字段

How to get sum of detail table fields in master table with update trigger

Firebird 3.0 数据库中有mastertable'factgad'和detailtable'recgad'

factgad: factgad_k(pr_k)...

recgad: recgad_k(pr_k), factgad_k(fk)...

当我更新 master table 时,我必须获取 table 的详细记录总和,但我无法编写正确的代码。当我尝试更新 master table 时,出现错误:

Error Message:
----------------------------------------
Too many concurrent executions of the same request.
Too many concurrent executions of the same request.
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, col: 3
At trigger 'FACTGAD_AU' line: 21, co...
---------------------------------------------------
SQLCODE: -693
SQLSTATE: 54001
GDSCODE: 335544663



create or alter trigger factgad_AU FOR factgad
ACTIVE AFTER UPDATE POSITION 0
AS
DECLARE VARIABLE newl DECIMAL(8, 4);
DECLARE VARIABLE oldl DECIMAL(8, 4);
DECLARE VARIABLE newd DECIMAL(8, 4);
DECLARE VARIABLE oldd DECIMAL(8, 4);
DECLARE VARIABLE FACTGAD_K INTEGER;
BEGIN
 select
        f.factgad_k,
        sum(r.fnewl*r.rgad),
        sum(r.foldl*r.rgad),
        sum(r.fnewd*r.rgad),
        sum(r.foldd*r.rgad)
   from recgad r, factgad f
   where f.factgad_k=new.factgad_k and r.factgad_k=f.factgad_k
   group by f.factgad_k
   into  :factgad_k,:NEWL, :OLDL, :NEWD, :OLDD;

  update factgad set
    factgad.NEWL=:NEWL,
    factgad.OLDL=:OLDL,
    factgad.NEWD=:NEWD,
    factgad.OLDD=:OLDD
   where factgad_k=:FACTGAD_K;
end

触发器有什么问题SQL?我尝试用 where f.factgad_k=43 更改 where 子句 where f.factgad_k=new.factgad_k 但出现相同的错误。重新启动 Firebird 服务没有任何变化。

奇怪的行为,在更新细节 table:

之后用细节总和 table 更新主 table 的更新触发器中出现了同样的错误
CREATE OR ALTER TRIGGER RECGAD_AU FOR RECGAD
ACTIVE AFTER UPDATE POSITION 0
AS
DECLARE VARIABLE NEWL DECIMAL(8, 4);
DECLARE VARIABLE OLDL DECIMAL(8, 4);
DECLARE VARIABLE NEWD DECIMAL(8, 4);
DECLARE VARIABLE OLDD DECIMAL(8, 4);
DECLARE VARIABLE FACTGAD_K INTEGER;
begin
 select
        r.factgad_k,
        sum(r.fnewl*r.rgad),
        sum(r.foldl*r.rgad),
        sum(r.fnewd*r.rgad),
        sum(r.foldd*r.rgad)
   from recgad r, factgad f
   where r.factgad_k=new.factgad_k and r.factgad_k=f.factgad_k
   group by r.factgad_k
   into  :factgad_k,:NEWL, :OLDL, :NEWD, :OLDD;

  update factgad set
    factgad.NEWL=:NEWL,
    factgad.OLDL=:OLDL,
    factgad.NEWD=:NEWD,
    factgad.OLDD=:OLDD
   where factgad_k=:FACTGAD_K;
end 

您正试图在 table FACTGAD 更新时触发的触发器中更新 table FACTGAD。换句话说,更新触发触发器,哪个更新,哪个触发触发器,等等。这最终会触发错误“同一请求的并发执行过多”.

你不应该在触发器中使用 UPDATE <table> 来触发相同 table 的更新。相反,您应该使用 BEFORE UPDATE 触发器,并将更新后的值分配给 NEW 上下文的列。在 INSERTUPDATE 上的 BEFORE UPDATE 触发器中,对 NEW 上下文的修改将更新要插入或更新的行。然而,在主 table 上触发的触发器中从细节 tables 重新计算值的总和没有多大意义:考虑如果主 table 永远不会更新会发生什么,但添加、删除或更新了详细信息行。

至于你的第二个触发器,我只能猜测你仍然有 FACTGAD 上的触发器,或者你有其他触发器导致 FACTGAD 和 [= 之间的更新周期21=].

顺便说一句,你执行的 select 不需要从 FACTGAD select,假设你在两者之间有一个外键约束。

TLDR:放弃触发器 factgad_AU,保留触发器 RECGAD_AU(但考虑将其设为 AFTER INSERT OR UPDATE)。

一般来说,master table 中的详细记录总和是不可能可靠的。最好的方法是通过触发细节 table 添加和减去数据,但在负载下它最终会导致更新冲突。您的触发器将在并发环境中以完全错误的值结束。

通常 select 中的聚合计算执行得很好。