我正在尝试在表上实现检查约束,以便在存在其中两列("Int_1"和"Int_2")已经具有我们尝试插入的值的记录的情况下无法插入记录例如:
ID Name Int_1 Int_2
1 Dave 1 2
Run Code Online (Sandbox Code Playgroud)
将(2,Steve,2,2)插入上表是可以的,(3,Mike,1,3),但是不允许插入Int_1和Int_2已经存在的值,即(4,Stuart,1 ,2)是非法的.
我认为定义我的表因此会起作用:
CREATE TABLE [Table](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](255) NOT NULL,
[Int_1] [int] NOT NULL,
[Int_2] [int] NOT NULL,
CONSTRAINT [chk_Stuff] CHECK (dbo.chk_Ints(Int_1, Int_2)=1))
Run Code Online (Sandbox Code Playgroud)
其中:dbo.chk_Ints定义为:
CREATE FUNCTION [dbo].[chk_Ints](@Int_1 int,@Int_2 int)
RETURNS int
AS
BEGIN
DECLARE @Result int
IF NOT EXISTS (SELECT * FROM [Table] WHERE Int_1 = @Int_1 AND Int_2 = @Int_2)
BEGIN
SET @Result = 1
END
ELSE
BEGIN
SET @Result = 0
END
RETURN @Result
END
GO
Run Code Online (Sandbox Code Playgroud)
当使用上面的组合时,如果我尝试插入任何记录,SQL告诉我,我已经破坏了我的检查约束.我可以从表中删除所有行并尝试插入第一条记录,SQL告诉我我已经破坏了我的约束,这是我不可能做到的!
我已经搜索了互联网很长一段时间,现在正在寻找检查约束的例子,其中UDF依赖于多个表列,但无济于事.关于为什么这可能不起作用的任何想法?
提前致谢 :)
And*_*y M 13
是的,这可能看起来令人费解,直到你意识到发生了什么,在这一点上它变得非常明显.
将为您尝试插入的行中的值调用该函数.但想想如何调用函数.它是一个调用它的检查约束.
接下来,考虑传递的参数.他们来自哪里?根据定义,检查约束从列Int_1和中获取它们Int_2.
因此,它将它们作为列值传递.但列值必须属于一行.在这种情况下它是哪一行?你试图插入的那个!
这意味着你的行被插入在这一点上,只有交易仍悬而未决.然而,行在表中的事实是至关重要的,因为这是函数找到并报告1结果的内容.
因此,正在发生的是这样的:
你试图插入一行,
该函数看到该行并表示已存在具有给定参数的行,
检查约束通过禁止插入来"作出反应",
插入物被回滚.
当然,现在你已经意识到这一切,很容易想出一个不同的检查重复的逻辑.基本上,您的函数应该"记住"新行已经在表中,因此它应该尝试确定它在表中的存在是否违反了您要建立的任何规则.例如,您可以计算与给定参数匹配的行,并查看结果是否不大于1:
IF (SELECT COUNT(*) FROM [Table] WHERE Int_1 = @Int_1 AND Int_2 = @Int_2) < 2
BEGIN
SET @Result = 1
END
ELSE
BEGIN
SET @Result = 0
END
Run Code Online (Sandbox Code Playgroud)
但是,在@a_horse_with_no_name建议的情况下,在这个作业的检查约束中使用函数的整个想法远不如仅在两列上添加唯一约束.做这个:
ALTER TABLE [Table]
ADD CONSTRAINT UQ_Table_Int1_Int2 UNIQUE (Int_1, Int_2);
Run Code Online (Sandbox Code Playgroud)
你可以忘记重复.