Reputation: 881
I have created a check constraint in SQL Server 2005, but this check constraint doesn't work. The SQL Server Management Studio tells me by an insert statement the following message:
Msg 547, Level 16, State 0, Line 1
The INSERT statement conflicted with the CHECK constraint "MY_CHECK_CONSTAINT". The conflict occurred in database "MY_DB", table "dbo.MY_TABLE", column 'MY_COLUMN'.
I have added the check constraint with the following code:
ALTER TABLE MY_TABLE WITH NOCHECK
ADD CONSTRAINT CK_MY_CHECK_CONSTRAINT CHECK (dbo.MY_FUNCTION(MY_PARAMETER)<1)
The calling function "MY_FUNCTION" returns an int.
My target is that if my function returns an int which is less than 1 the insert statement can successfully be completed and if the return value is bigger than 0 the insert statement has to be terminated.
My problem now is that my function returns the value 0 but the insert statement has been terminated always. What am I doing wrong?
The code of my function is the following:
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
Thanks for your help.
Upvotes: 0
Views: 1981
Reputation: 39437
I was able to reproduce your problem in 100%. Try this new
example below. Now my table table1 is empty, and I cannot insert
any number into it :) Very interesting situation, absolutely the
same as yours, I believe.
"Maybe when your UDF code is executed, it already sees this same
row which you're just trying to insert (it sees it's in the table).
I don't know the inner workings and don't have much time now to check it.
But that could be the issue. My UDF doesn't perform a check based on some
SELECT in the same table, that's what's conceptually different between
your example and my example."
OK, after 5 more minutes of research, turns out my guess was right.
When your UDF is called, it sees the row you're just trying
to insert.
See the accepted answer here.
Check constraint UDF with multiple input parameters not working
So - mystery uncovered, it seems :)
--- 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
Upvotes: 2
Reputation: 39437
1) Maybe you can try this in your code:
SELECT @return = COUNT(MY_COLUMN)
FROM MY_TABLE WHERE MY_COLUMN = @MY_PARAMETER
instead of what you did.
2) Try naming the variable not @return but e.g. @result.
3) Try walking your function outside of its normal call.
4) Also, you might want to try this test below. I don't see any issues with it ... But OK, it's not 100% the same as yours.
This check constraint below works fine and uses my user defined function 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
Upvotes: 0