Search code examples
sql-servert-sqlcheck-constraints

why is t-sql allowing me to violate a check constraint that uses a UDP?


I have a check constraint on a table in my DB. My understanding of a check is it sets a logical condition that must be true for records in a table.

USE [myDB]
GO

ALTER TABLE [dbo].[myTable]  WITH CHECK ADD  CONSTRAINT [oneProgramPerTest] CHECK  (([dbo].[howManyProgPerTest]([TestId])<(2)))
GO

ALTER TABLE [dbo].[myTable] CHECK CONSTRAINT [oneProgramPerTest]
GO

But I am able to do an update to the table that breaks the constraint. After the update, this query returns 9 records:

select COUNT (*) from myDB.dbo.myTable where myDB.[dbo].[howManyProgPerTest](testID)>1

What might be going on?


Solution

  • Beware using UDFs in check constraints for this reason. This blog post describes your issue. To summarize:

    (A UDF) will on the surface do its job, as long as you INSERT into the table. But if you update a row and only set the otherColumn for some row from 0 to 1, then the check constraint will not be checked.

    The optimizer is smart enough to understand that the update doesn't change anything that we refer to in our CHECK constraint, so why bother checking the constraint?

    End result here is that the constraint doesn't do what we want it to do. Use a trigger instead (or some other method).

    (Emphasis added)