Tuesday, 19 May 2009

Enforcing uniqueness on a combination of columns in different tables

Given the above schema, I had the need to create some kind of constraint that would prevent a particular gameTypeId being linked to more than one lobby. I thought of a trigger or perhaps create a new LobbyGameType table, but this would require manual updating.

The solution I found was to create a new view with a unique index on it, and happily this works in standard edition too!

These are the steps I took:
  1. CREATE VIEW vwLobbyGameType
    WITH SCHEMABINDING
    AS
    SELECT L.lobbyId, TSGT.gameTypeId
    FROM dbo.Lobby L
    INNER JOIN dbo.LobbyTableSet LTS
    ON L.lobbyId = LTS.lobbyId
    INNER JOIN dbo.TableSetGameType TSGT
    ON LTS.tableSetId = TSGT.tableSetId

    GO

  2. SET QUOTED_IDENTIFIER ON
    SET ANSI_NULLS ON
    GO
    CREATE UNIQUE CLUSTERED INDEX [CIX_vwLobbyGameType]
    ON
    vwLobbyGameType(lobbyId,gameTypeId)
    GO
Upon trying to insert a record into TableSetGameType that would have resulted in a gameTypeId being linked to more than one tableSetId in one lobby, I got the following error:
Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.vwLobbyGameType' with unique index 'CIX_vwLobbyGameType'.
The statement has been terminated.

It works!!! :)