SQL Server检查列上的约束和另一列中的值

Ali*_*n I 1 sql sql-server sql-server-2008-r2

我有一张桌子

PKID    FID     RESULT
======================
1       1       1
2       1       2 
3       1       2 
4       1       3 
4       2       1 
4       2       1
Run Code Online (Sandbox Code Playgroud)

我正在尝试设置一个约束,这样如果已存在FID = 1且RESULT = 3的记录,我就无法在表中插入另一条FID = 1的记录.

我试图创建这样的函数

CREATE FUNCTION MyCheck
(
    -- Add the parameters for the function here
    @FID int
)
RETURNS bit
AS
BEGIN
    IF EXISTS (SELECT  PKID FROM MyTable WHERE (RESULT= 3) AND (FID= @FID))
        return 1
    return 0
END
Run Code Online (Sandbox Code Playgroud)

但是当我使用这个函数创建约束时:

ALTER TABLE MyTable
    WITH CHECK ADD CONSTRAINT CK_Code
    CHECK (MyCheck(FID) = 0)
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

ALTER TABLE语句与CHECK约束"CK_Code"冲突.冲突发生在数据库"MyDB",表"MyTable",列'FID'中.

Dam*_*ver 6

有了更新/澄清,是的,我们现在必须使用触发器1.我们不能再声明,因为没有办法查看一组数据,比如说:

FID     RESULT
==============
1       1
1       3 
1       2 
1       2 
2       1 
2       1
Run Code Online (Sandbox Code Playgroud)

并确定该数据是否合法.如果行是插入的最后一行,则是合法的(1,3).这是不是合法的,如果任何其他行的FID的1是插入的最后一行.

那么,触发它是:

CREATE TRIGGER T_PreventBadInsert
ON MyTable
AFTER INSERT
AS
    SET NOCOUNT ON;
    IF EXISTS(select * from inserted i inner join MyTable m
                 on i.PK <> m.PK and i.FID = m.FID
                    and m.Result = 3)
    BEGIN
        RAISERROR('Cannot insert a new row once one row has result 3',16,1);
        ROLLBACK;
    END
Run Code Online (Sandbox Code Playgroud)

请注意,INSERT如果一行违反了要求,这将中止整个语句.它也将中止一个INSERT试图添加两行相同FID,其中一个排的有RESULT3个.

我们可能还想编写一个更新触发器,禁止更改FID任何现有行的值或执行类似的检查,但我不知道您的要求是什么.

如果您使用的是SQL Server 2008或更高版本,则只需过滤索引即可:

CREATE UNIQUE INDEX IX_Max1Result3 ON MyTable (FID) WHERE Result = 3
Run Code Online (Sandbox Code Playgroud)

(并且你的函数/检查不起作用,因为那里没有任何东西可以阻止一行将自己当作"现有"行)


1有一个强有力的词.可能还有其他方法,但我认为触发器可能是最简单的方法.