SQL Server检查约束以防止特定重复

时间:2015-09-16 21:16:32

标签: sql-server indexing constraints

我有这样的数据结构:

CREATE TABLE test_Bundles 
(
   BundleId INT,
   UserId INT,
   status INT
)

INSERT INTO test_Bundles VALUES (1, 1, 1)
INSERT INTO test_Bundles VALUES (2, 1, 3)
INSERT INTO test_Bundles VALUES (3, 1, 3)
INSERT INTO test_Bundles VALUES (4, 2, 1)
INSERT INTO test_Bundles VALUES (5, 2, 3)
INSERT INTO test_Bundles VALUES (6, 2, 3)
GO

用户只能拥有一个status = 1的捆绑包。但是他们可以有很多地方= status = 2或status = 3或status = 4.

有人能想到在SQL Server中强制执行此规则的方法吗?

2 个答案:

答案 0 :(得分:4)

好吧,您可以自然地使用触发器,或者您可以使用唯一的过滤索引(如果您运行的是SQL Server 2008或更高版本),例如:

create unique index ix_tmp 
on test_Bundles (UserId, status) where status = 1;

如果您更喜欢采用触发路由(适用于任何合理版本的SQL Server),它看起来像这样:

create trigger tgrTmp on test_Bundles for insert, update 
as
begin;

if exists(  select  * 
            from test_Bundles t
            join inserted i 
            on t.UserId = i.UserId
            and t.BundleId != i.BundleId
            where t.status = 1 
            and i.status = 1)
begin;
    raiserror ('unique violation',16,1);
    rollback;
end;

end;

答案 1 :(得分:1)

create trigger trigPreventStatus1Duplicates
On test_Bundles for insert, update
as 
declare @errMsg varchar(200) = 
     'You cannot enter more than one status 1 bundle per user.'
set NoCount On
   begin
       if exists (Select * from inserted i 
                    join test_Bundles b 
                       on b.userId = i.userId 
                          and b.bundleId != i.bundleId
                  where b.status = 1
                  group by i.UserId
                  having count(*) > 1)
          begin
              rollback transaction
              raiserror(errMsg , 16, 1)
          end  
   end