问题描述
在 Interbase 2009 db 中,我有主表和明细表(Tmaster、Tdetails)。
老师:
master_id(pk) | DocSumma | DocSummaDol |
---|
详细信息:
det_id | master_id(fk) | 价格1,价格2 | qnt |
---|
在我删除/更新子表(Tdetails)中的记录后,必须更新主表(Tmaster)中的总和。
我有两个问题:
- 如果过程包含这个 if 子句:
if (m.DocSumma=0) then begin delete from Tmaster m where m.master_id=:master_id; end
它返回这个错误:
列不属于引用的表。动态 sql 错误。 sql 错误代码 = -206。列未知。
- 如果没有 if 子句,我有第二个问题:程序运行非常慢。它会在 13 小时后结束 :)
有时在 IBExpert 中我会收到此错误:
发生算术溢出或被零除。算术 异常、数字溢出或字符串截断。 sqlCODE:-802 GDSCODE:335544321
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
解决方法
问题不在于删除语句,问题在于if (m.DocSumma=0) then begin
。您不能在 PSQL 块中引用这样的表。您需要将该列值显式分配给局部变量。
例如,类似于:
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;
-
其中一些更改最好通过
TDETAILS
或TMASTER
上的触发器完成,而不是使用延迟的显式重新计算。