为啥这个 Check 约束不起作用?

Posted

技术标签:

【中文标题】为啥这个 Check 约束不起作用?【英文标题】:Why doesn't this Check constraint work?为什么这个 Check 约束不起作用? 【发布时间】:2013-11-26 09:09:36 【问题描述】:

我在 SQL Server 2005 中创建了一个检查约束,但是这个检查约束不起作用。 SQL Server Management Studio 通过插入语句告诉我以下消息:

消息 547,第 16 级,状态 0,第 1 行 INSERT 语句与 CHECK 约束“MY_CHECK_CONSTAINT”冲突。冲突发生在数据库“MY_DB”、表“dbo.MY_TABLE”、列“MY_COLUMN”中。

我已经使用以下代码添加了检查约束:

ALTER TABLE MY_TABLE WITH NOCHECK
ADD CONSTRAINT CK_MY_CHECK_CONSTRAINT CHECK (dbo.MY_FUNCTION(MY_PARAMETER)<1)

调用函数“MY_FUNCTION”返回一个 int。

我的目标是,如果我的函数返回一个小于 1 的 int 语句可以成功完成,如果返回值大于 0 则插入语句必须终止。

我现在的问题是我的函数返回值 0 但插入语句总是终止。我做错了什么?

我的函数代码如下:

CREATE FUNCTION MY_FUNCTION(@MY_PARAMETER uniqueidentifier) 
RETURNS int 
AS 
BEGIN 
    declare @return int = 0
    SET @return = (SELECT COUNT(MY_COLUMN) FROM MY_TABLE WHERE MY_COLUMN= @MY_PARAMETER )
return @return 
END 

感谢您的帮助。

【问题讨论】:

错在你的假设函数返回0是不正确的。但是我们无法告诉您为什么它不正确,因为您没有向我们展示它的代码。 我现在已经添加了我的函数代码。希望对您有所帮助。 只需在MY_COLUMN 上添加一个唯一约束。不要为此尝试使用带有标量 UDF 的检查约束。 嗨 Martin,我不能使用唯一约束,因为 MY_COLUMN 可以为 NULL。 【参考方案1】:

我能够 100% 重现您的问题。试试这个新的 下面的例子。现在我的表 table1 是空的,我无法插入 任何数字进入它:) 非常有趣的情况,绝对是 和你一样,我相信。

“也许当你的 UDF 代码被执行时,它已经看到了同样的 您只是尝试插入的行(它看到它在表中)。 我不知道内部工作原理,现在没有太多时间检查它。 但这可能是问题所在。我的 UDF 不执行基于某些 的检查 SELECT 在同一张表中,这就是 你的榜样和我的榜样。”

好的,经过 5 分钟的研究,结果证明我的猜测是正确的。 当您的 UDF 被调用时,它会看到您正在尝试的行 插入。

在此处查看接受的答案。

Check constraint UDF with multiple input parameters not working

所以 - 似乎揭开了谜团:)

--- 1 ---

USE [test]
GO

/****** Object:  UserDefinedFunction [dbo].[ContainsNumber]    Script Date: 11/26/2013 07:06:41 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[ContainsNumber]
(
        @number int
)
RETURNS INT AS

BEGIN

declare @result int

select @result = count(*)
from test.dbo.table1
where
number = @number

if (@result > 0) 
begin
    set @result = 1
end

return @result

END


GO



--- 2 ---

USE [test]
GO

/****** Object:  Table [dbo].[table1]    Script Date: 11/26/2013 07:06:33 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[table1](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [number] [int] NULL,
 CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[table1]  WITH CHECK ADD  CONSTRAINT [CK_table1] CHECK  (([dbo].[ContainsNumber]([number])=(0)))
GO

ALTER TABLE [dbo].[table1] CHECK CONSTRAINT [CK_table1]
GO

【讨论】:

非常感谢您的帮助 :) 现在一切正常。这就是解决方案。【参考方案2】:

1) 也许你可以在你的代码中试试这个:

SELECT @return = COUNT(MY_COLUMN) 
FROM MY_TABLE WHERE MY_COLUMN = @MY_PARAMETER

而不是你所做的。

2) 尝试将变量命名为不是 @return 而是例如@结果。

3) 尝试在正常调用之外执行您的函数。

4) 此外,您可能想尝试以下测试。 我看不出有任何问题......但是好的, 它和你的不是 100% 一样。

下面的这个检查约束工作正常并使用 我的用户定义函数 IsEvenNumber。

----- 1 -----

USE [test]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO



CREATE FUNCTION [dbo].[IsEvenNumber]
(
        @number int
)
RETURNS INT AS

BEGIN

declare @result int

set @result = 1

if (((@number) % 2) <> 0)
begin
    set @result = 0
end


return @result


END



GO




----- 2 -----


USE [test]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[table1](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [number] [int] NULL,
 CONSTRAINT [PK_table1] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[table1]  WITH CHECK ADD  CONSTRAINT [CK_Table1] CHECK  (([dbo].[IsEvenNumber]([number])<(1)))
GO

ALTER TABLE [dbo].[table1] CHECK CONSTRAINT [CK_Table1]
GO



----- 3 -----


insert into table1(number) values (3) -- OK

insert into table1(number) values (10) -- FAILED

insert into table1(number) values (0) -- FAILED

insert into table1(number) values (5) -- OK

【讨论】:

如果我执行您的解决方案,一切正常,但是当我尝试对我的函数和表执行相同操作时,我收到以下错误消息:Msg 547, Level 16, State 0, Line 1 ALTER TABLE 语句与 CHECK 约束“CK_MY_CONSTRAINT”冲突。冲突发生在数据库“MY_DB”、表“dbo.MY_TABLE”、列“MY_COLUMN”中。 我不知道为什么,但是我不能改变我的表来添加检查约束而不放置 NOCHECK。 我尝试使用固定值作为参数在外部调用我的函数,我确信我的函数可以按我的意愿工作。 也许当你的 UDF 代码被执行时,它已经看到了你试图插入的同一行(它看到它在表中)。我不知道内部工作原理,现在没有太多时间检查它。但这可能是问题所在。我的 UDF 不会根据同一张表中的某些 SELECT 执行检查,这就是你和我在概念上的不同。 也许这就是问题所在,但我想知道为什么我不能在没有 NOCHECK 扩展的情况下更改我的表并添加检查约束

以上是关于为啥这个 Check 约束不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 中的 CHECK 约束不起作用

为啥这些约束不起作用?

为啥这些约束不起作用?

Python:为啥这个程序不起作用?

为啥自动布局约束不起作用?

为啥默认约束在mysql中不起作用? [复制]