创建CHECK约束要求INKOOPBEDRAG大于PRIJS_PER_D时报错如何解决
问题原因
标准SQL规定,CHECK约束仅可引用当前表的字段,无法直接查询引用其他关联表的字段,这是你编写的约束执行报错的根本原因。
解决实现方案
下面提供两种主流的跨表字段校验实现方式:
- 方案1:触发器实现(兼容性最高,全主流数据库支持)
在INKOOPOVEREENKOMST表的INSERT、UPDATE事件上创建触发器,每次数据写入/更新时关联ARTIKEL表做字段校验,不符合规则则拦截操作。
以SQL Server为例,示例代码如下:
CREATE TRIGGER TRG_Check_Inkoopbedrag ON INKOOPOVEREENKOMST FOR INSERT, UPDATE AS BEGIN SET NOCOUNT ON; -- 校验是否存在不符合规则的数据 IF EXISTS ( SELECT 1 FROM inserted i INNER JOIN ARTIKEL a ON i.BARCODE = a.BARCODE WHERE i.INKOOPBEDRAG <= a.PRIJS_PER_D ) BEGIN RAISERROR('INKOOPBEDRAG字段值必须大于对应商品的PRIJS_PER_D值', 16, 1); ROLLBACK TRANSACTION; END END
- 方案2:用户定义函数+CHECK约束(部分数据库支持,如SQL Server)
先创建自定义函数根据BARCODE查询对应ARTIKEL表的PRIJS_PER_D值,再在CHECK约束中调用该函数完成校验。该方案语法更简洁,但仅支持兼容UDF在CHECK中调用的数据库,且性能低于触发器方案。
示例代码如下:
-- 自定义查询PRIJS_PER_D的函数 CREATE FUNCTION dbo.Func_Get_Prijs_Per_D(@InputBarcode VARCHAR(100)) RETURNS DECIMAL(12,2) AS BEGIN DECLARE @ResultPrijs DECIMAL(12,2); SELECT @ResultPrijs = PRIJS_PER_D FROM ARTIKEL WHERE BARCODE = @InputBarcode; RETURN @ResultPrijs; END GO -- 创建CHECK约束 ALTER TABLE INKOOPOVEREENKOMST ADD CONSTRAINT CK_inkoopbedraghogerdprijs CHECK (INKOOPBEDRAG > dbo.Func_Get_Prijs_Per_D(BARCODE));
补充说明:上述两种方案默认仅在
INKOOPOVEREENKOMST表数据变更时做校验,如果你需要在ARTIKEL表的PRIJS_PER_D字段修改时也校验历史关联数据是否符合规则,需要额外在ARTIKEL表的UPDATE事件上增加对应触发器。
内容的提问来源于stack exchange,提问作者Mafklaper
相关产品推荐
相关产品推荐

