我在 Firebird 3 db 中有 2 个表 - 主表“Docs”用于输出文档,明细表“Recs”用于已售商品。
Docs
的列:doc_id、summaRecs
的列: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
正如 Freddie Bell 在评论中提到的,问题在于您正在使用隐式内部联接。这意味着,当
RECS
中的一行没有行时,由于 DOCS
的存在,将不会有行。您要么需要按照 Freddie 的建议使用显式 GROUP BY
,仅从
LEFT JOIN
中选择而不加入 RECS
(并省略 DOCS
),或者更简单,只需使用相关子执行更新选择而不先单独执行选择:GROUP BY
即使
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
中没有行,这也会起作用,因为缺少
RECS
,当 GROUP BY
中没有匹配行时,这将生成一行。