使用函数检查约束

时间:2014-10-10 15:38:41

标签: sql-server constraints sql-function check-constraint

我有一个名为Users的表,其中包含以下列:UserID(int)UserName(nvarchar),Password(nvarchar),isActive(bit - true / false)。

我想要做的是只有在禁用具有此用户名的所有其他用户时才允许插入重复的用户名。

我创建了这个函数:

ALTER FUNCTION [dbo].[isActiveUsername]
    (@username nvarchar(15))
RETURNS bit
AS

BEGIN

IF EXISTS
            (
                SELECT * 
                FROM Users
                WHERE isActive = 1 AND UserName = @username
            )
            RETURN 1
    RETURN 0
END

如果有这个用户名的活跃用户,则此函数将返回true,否则返回false。

之后,我根据此函数返回的值创建了检查约束:

ALTER TABLE [dbo].[Users]  
WITH NOCHECK ADD CHECK  (([dbo].[isActiveUsername]([UserName])=(0)))

如果没有此用户名的活跃用户,请允许插入... 但由于某种原因,当我尝试插入新用户时,没有遇到我尝试的用户名,我收到此错误:

Msg 547, Level 16, State 0, Line 2
The INSERT statement conflicted with the CHECK constraint "CK__Users__UserName__4D94879B". The conflict occurred in database "Chat", table "dbo.Users", column 'UserName'.
The statement has been terminated.

请帮忙吗? 非常感谢!!

2 个答案:

答案 0 :(得分:2)

对于MSSQL 2008及更高版本,请在isActive上创建filtered index

create unique index ux_UserName on dbo.Users(Username) where isActive = 1;

这允许您对数据子集强制执行唯一性。

答案 1 :(得分:1)

问题是INSERTCHECK约束运行之前发生,因此在函数运行之前表中始终有一个用户。将您的功能更改为:

ALTER FUNCTION [dbo].[isActiveUsername]
    (@username nvarchar(15))
RETURNS bit
AS
BEGIN
    IF  (SELECT COUNT(*) FROM Users WHERE isActive = 1 AND UserName = @username) > 1
    BEGIN
        RETURN 1
    END

    RETURN 0

END