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

时间:2014-01-24 09:44:32

标签: 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

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

我试图创建一个像这样的函数

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

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

ALTER TABLE MyTable
    WITH CHECK ADD CONSTRAINT CK_Code
    CHECK (MyCheck(FID) = 0)

我收到此错误:

  

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

2 个答案:

答案 0 :(得分:6)

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

FID     RESULT
==============
1       1
1       3 
1       2 
1       2 
2       1 
2       1

并决定该数据是否合法。如果(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

请注意,如果一行违反了要求,这将中止整个INSERT语句。它还会中止INSERT尝试为同一FID添加两行,其中一行的行RESULT为3。

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

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

CREATE UNIQUE INDEX IX_Max1Result3 ON MyTable (FID) WHERE Result = 3

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


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

答案 1 :(得分:1)

你的代码绝对没问题。 只是改变你的功能,

Alter FUNCTION dbo.MyCheck
(
    -- Add the parameters for the function here
    @FID int
)
RETURNS bit
AS
BEGIN
    IF  (SELECT  count(PKID) FROM tmp WHERE (RESULT= 3) AND (FID= @FID))>1
        return 1
    return 0
END

另请注意,如果您已经有重复记录,请首先检查您的数据。如果您已经重复了数据,那么您就无法创建约束。

运行,

  

从表中选择fid,其中结果= 3组由fid计数(fid)&gt; 1

如果你得到行,那么你需要删除它。