Firebird 触发方式如何正确

问题描述 投票:0回答:1

我在 Firebird 3 db 中有 2 个表 - 主表“Docs”用于输出文档,明细表“Recs”用于已售商品。

  • Docs
    的列:doc_id、summa
  • Recs
    的列:id、doc_id、商品、价格、qnt

当客户取消销售时,此记录保留在详细表中,没有删除它,更新触发器更新主表的总计

summa

触发器在最后一条记录保留在输出表中之前运行良好。但是,如果客户取消上次销售并且详细数据集变空,则触发器无法正常工作并显示最后一条记录的

summa
而不是 0。

如何纠正这个触发器?

CREATE OR ALTER TRIGGER RECS_AU FOR Recs
 ACTIVE AFTER UPDATE POSITION 0
 AS
  DECLARE VARIABLE Price DECIMAL(12, 4);
  DECLARE VARIABLE Doc_id INTEGER;
  DECLARE VARIABLE OLD_Price DECIMAL(12, 4);
  BEGIN
   select 
    r.Doc_id,
    coalesce(sum(r.Price*r.Qnt),0)
   from Recs r, Docs d
   where r.Doc_id=new.Doc_id and r.Doc_id=d.Doc_id and r.status<>'deleted'
   group by r.Doc_id
   into :Doc_id, :Summa;
    
     update Docs set
      Docs.Summa=:Summa:
     where Doc_id=:Doc_id;

我知道问题在于编写正确的 SQL,而不是触发器。数据集变空后,它返回空记录集。为什么在数据集为空的情况下合并不起作用并且不将

summa
显示为 0?

SELECT 
    doc_id,
    coalesce(SUM(cast((r.price*r.qnt) as decimal(18,4))),0) as summa
FROM 
    recs r
WHERE 
    doc_id= :doc_id AND status <> 'deleted'
GROUP BY
    doc_id
sql triggers firebird
1个回答
0
投票

正如 Freddie Bell 在评论中提到的,问题在于您正在使用隐式内部联接。这意味着当

RECS
中没有行时,对于
DOCS
中的行,则不会有行。

您要么需要按照 Freddy 的建议使用显式

LEFT JOIN
,或者更简单,只需使用相关选择执行更新,而无需首先执行选择:

update DOCS d set d.Summa = (
  select coalesce(sum(r.Price*r.Qnt), 0)
  from RECS r
  where r.DOC_ID = d.DOC_ID and r.STATUS <> 'deleted'
)
where d.DOC_ID = :NEW.DOC_ID
© www.soinside.com 2019 - 2024. All rights reserved.