我有一张桌子
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'。
答案 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
如果你得到行,那么你需要删除它。