2

Firebird 3.0 数据库中有主表“factgad”和详细表“recgad”。

factgad : factgad_k(pr_k)...

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

在此处输入图像描述

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

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 子句where f.factgad_k=new.factgad_kwhere f.factgad_k=43但出现相同的错误。重新启动 Firebird 服务没有任何改变。

奇怪的行为,更新触发器后出现相同的错误,它在更新详细表后用详细表的总和更新主表:

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 
4

2 回答 2

2

您正试图在更新表FACTGAD时触发的触发器中更新表FACTGAD。换句话说,更新触发触发器,更新,触发触发器等等。这最终会触发错误"Too many concurrent executions of the same request"

您不应该UPDATE <table>在同一个表的更新时触发的触发器中使用。相反,您应该使用BEFORE UPDATE触发器,并将更新的值分配给NEW上下文的列。在or上的BEFORE UPDATE触发器中,上下文的修改将更新要插入或更新的行。但是,在主表上触发的触发器中重新计算明细表的值的总和没有多大意义:考虑如果主表从未更新,但添加、删除或更新明细行会发生什么情况。INSERTUPDATENEW

至于你的第二个触发器,我只能猜测你仍然有触发器FACTGAD,或者你有其他触发器导致 和 之间的更新FACTGAD循环RECGAD

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

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

于 2021-02-21T14:57:08.947 回答
0

一般来说,要获得可靠的主表中的详细记录总和是不可能的。最好的方法是通过详细信息表上的触发器添加和减去数据,但在负载下它最终会出现更新冲突。您的触发器将在并发环境中以完全错误的值结束。

通常 select 中的聚合计算性能足够好。

于 2021-02-21T20:17:25.660 回答