检查多个输入参数不起作用的约束UDF

时间:2013-09-22 17:03:59

标签: sql-server tsql

我正在尝试对表执行检查约束,以便在存在其中两列(“Int_1”和“Int_2”)已经具有我们的值的记录的情况下无法插入记录试图插入Eg:

ID     Name     Int_1     Int_2
1      Dave       1         2

将(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))

其中: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

当使用上面的组合时,如果我尝试插入任何记录,SQL会告诉我我已经破坏了我的检查约束。我可以从表中删除所有行并尝试插入第一条记录,SQL告诉我我已经破坏了我的约束,这是我不可能做到的!

我已经在互联网上搜索了很长一段时间,现在正在寻找检查约束的例子,其中UDF依赖于多个表列,但无济于事。关于为什么这可能不起作用的任何想法?

提前致谢:)

1 个答案:

答案 0 :(得分:12)

是的,这个可能看起来莫名其妙,直到你意识到发生了什么,此时它变得非常明显。

为您尝试插入的行中的值调用该函数。但想想如何调用函数。它是一个调用它的检查约束。

接下来,考虑传递的参数。他们来自哪里?根据定义,检查约束从列Int_1Int_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

然而,在这个作业的检查约束中使用函数的整个想法非常低劣只是在两列上添加唯一约束,如suggested by @a_horse_with_no_name。这样做:

ALTER TABLE [Table]
ADD CONSTRAINT UQ_Table_Int1_Int2 UNIQUE (Int_1, Int_2);

你可以忘记重复。