详细删除记录 table 后更新主 table 的过程出错

Error in procedure which updates master table after deleting records in detail table

在 Interbase 2009 数据库中,我有 master 和 detail tables(Tmaster, Tdetails)。

Tmaster:

master_id(pk) DocSumma DocSummaDol

T详情:

det_id master_id(fk) price1,price2 qnt

在我 delete/update 子 table(Tdetails) 过程中记录后必须更新主 table(Tmaster) 中的摘要。

我有两个问题:

  1. 如果过程包含此 if 子句:
if (m.DocSumma=0) then begin delete from Tmaster m where m.master_id=:master_id; end

它returns这个错误:

Column does not belong to referenced table. Dynamic SQL Error. SQL error code = -206. Column unknown.

  1. 如果没有 if 子句,我会遇到第二个问题:程序工作 非常慢。 13 小时后结束:)

有时在 IBExpert 中我会收到此错误:

Arithmetic overflow or division by zero has occurred. arithmetic exception, numeric overflow, or string truncation. SQLCODE: -802 GDSCODE: 335544321

我的 Psql 代码有什么问题?

alter procedure sp_recalculate_summa
as
    declare variable master_id integer;
    declare variable det_id integer;
    declare variable sum1 decimal(8,4) ;
    declare variable sum2 decimal(8,4) ;
    begin
        for  select m.master_id
        from Tmaster m
        into :master_id
        do begin
            sum1=0;
            sum2=0;
            for select det_id,
                      sum(d.price1*d.qnt)as summa1,
                      sum(d.price2*d.qnt)as summa2
            from Tdetails d, Tmaster m
            where d.det_id=:master_id
            group by det_id
            into :det_id,:sum1,:sum2
            do
                if (m.DocSumma=0) then begin 
                    delete from Tmaster m where m.master_id=:master_id; 
                end 
                Else begin
                    update Tmaster set DocSumma=:sum1 where master_id=:master_id;
                    update Tmaster set DocSummaDol=:sum2 where master_id=:master_id;
                end
        end
    end

问题不在于 delete 语句,而在于 if (m.DocSumma=0) then begin。您不能像在 PSQL 块中那样引用 table。您需要将该列值显式分配给局部变量。

例如:

alter procedure sp_recalculate_summa
as
    declare variable master_id integer;
    declare variable DocSumma decimal(8,4);
    declare variable det_id integer;
    declare variable sum1 decimal(8,4) ;
    declare variable sum2 decimal(8,4) ;
    begin
        for  select m.master_id, m.DocSumma
        from Tmaster m
        into master_id, DocSumma
        do begin
            sum1=0;
            sum2=0;
            for select det_id,
                      sum(d.price1*d.qnt)as summa1,
                      sum(d.price2*d.qnt)as summa2
            from Tdetails d, Tmaster m
            where d.det_id=:master_id
            group by det_id
            into det_id,sum1,sum2
            do
                if (DocSumma=0) then begin 
                -- etc..
                end
        end
    end

补充说明:

  • 我质疑条件 if (m.DocSumma=0) then begin 的正确性(if (DocSumma=0) then begin 在我提议的更改中),这不应该是 if (sum1 = 0) then begin 吗?就像,它应该使用更新的总和,而不是旧的总和。

  • 还有,为什么要更新TMASTER两次?使用单个更新会更有效:

    update Tmaster set DocSumma=:sum1, DocSummaDol=:sum2 where master_id=:master_id;
    
  • 其中一些更改最好通过 TDETAILSTMASTER 上的触发器来完成,而不是使用延迟的显式重新计算。