复杂的多列唯一约束

时间:2013-05-29 21:44:40

标签: sql-server sql-server-2008 unique-constraint

我有一个包含10列的表,但只关心3列。想象一下,我的表看起来像这样:

CREATE TABLE MyTable ( RowID int IDENTITY(1,1), UserID int, NodeID int, RoleID int )

我需要的是一个强制执行以下操作的约束:UserID和RoleID对于每个NodeID都必须是唯一的(即用户在多个节点中不能具有相同的角色)。换句话说,我想允许

INSERT MyTable (UserID, NodeID, RoleID) SELECT 1, 1, 1

但不允许

INSERT MyTable (UserID, NodeID, RoleID) SELECT 1, 2, 1

如果发生了第一次插入,因为这会导致用户在多个节点中拥有角色。

希望这很简单,我只是让它变得比我脑中需要的更复杂。

2 个答案:

答案 0 :(得分:2)

由于您的约束取决于其他行中的数据,因此排除了筛选的索引。 IMO可行的选择可能是一个触发器。这样的触发器看起来像这样:

CREATE TRIGGER dbo.MyTrigger ON dbo.Q1
    AFTER INSERT, UPDATE
AS
    DECLARE @userId INT, @Id INT, @roleId INT, @exists INT;

    SELECT TOP 1
            @userId = userID
           ,@roleId = roleID
           ,@Id = Id
    FROM    inserted;    

    SELECT TOP 1
            @exists = Id
    FROM    Q1
    WHERE   userId = @userId
            AND roleID = @roleID AND Id<> @Id;    

    IF ISNULL(@exists, 0) > 0 
        BEGIN           
            -- you would want to either undo the action here when you use an 'after' trigger
            -- because as the name implies ... the after means the record is allready inserted/updated          
            RAISERROR ('No way we would allow this.', 16, 1);
        END
        -- else
        -- begin
            -- another alternative would be to use a instead of trigger, which means the record
            -- has not been inserted or updated and since that type of trigger runs the trigger 'instead of'
            -- updating or inserting the record you would need to do that yourself. Pick your poison ...
        -- end
GO

答案 1 :(得分:1)

唯一索引应该强制执行您的要求

CREATE UNIQUE NONCLUSTERED INDEX [idx_Unique] ON [dbo].[MyTable] 
(
    [UserID] ASC,
    [NodeID] ASC,
    [RoleID] ASC
)

从评论中我想你需要两个独特的指数

CREATE UNIQUE NONCLUSTERED INDEX [idx_User_Node] ON [dbo].[MyTable] 
(
    [UserID] ASC,
    [NodeID] ASC
)
GO
CREATE UNIQUE NONCLUSTERED INDEX [idx_User_Role] ON [dbo].[MyTable] 
(
    [UserID] ASC,
    [RoleID] ASC
)