编写SQL触发器验证:每条Bill记录需对应至少一条Detail表记录
实现Bill与Detail的关联校验(无结构修改方案)
一、排查现有违规记录
首先清理数据库中已存在的无明细Bill,用以下SQL查询这类记录:
左连接查询
SELECT b.BillID FROM Bill b LEFT JOIN Detail d ON b.BillID = d.BillID WHERE d.BillID IS NULL;
NOT EXISTS查询
SELECT BillID FROM Bill WHERE NOT EXISTS ( SELECT 1 FROM Detail WHERE Detail.BillID = Bill.BillID );
查出结果后,要么给这些Bill补全Detail明细,要么直接删除无效Bill——否则后续触发器会拦截相关操作。
二、创建触发器拦截非法操作
由于不能修改数据库结构,我们通过触发器确保后续操作不会产生无明细的Bill。这个触发器会处理两种违规场景:删除某Bill的最后一条明细、修改明细的BillID导致原Bill无明细。
触发器代码
CREATE TRIGGER trg_PreventOrphanedBill ON Detail AFTER DELETE, UPDATE AS BEGIN SET NOCOUNT ON; -- 检查操作后是否出现无明细的Bill IF EXISTS ( SELECT 1 FROM Bill b WHERE b.BillID IN (SELECT BillID FROM deleted) AND NOT EXISTS ( SELECT 1 FROM Detail d WHERE d.BillID = b.BillID ) ) BEGIN RAISERROR ('操作会导致Bill无对应明细,已回滚事务', 16, 1); ROLLBACK TRANSACTION; END END
触发器说明
- 触发时机:Detail表执行DELETE或UPDATE后触发
- 核心逻辑:针对被操作的BillID(删除明细所属的Bill,或更新前的BillID),检查是否还有剩余明细。如果没有,立即抛出错误并回滚操作。
- 业务兼容:如果你的流程允许先创建Bill再补明细,这个触发器不会拦截Bill的插入操作——因为插入Bill时未涉及Detail表,触发器不触发。如果需要严格禁止无明细Bill存在,建议用事务包裹Bill和Detail的插入操作,或者定期执行清理脚本。
内容的提问来源于stack exchange,提问作者Ho Quang Lam
相关产品推荐
相关产品推荐

