2013-05-01 103 views
6

我有三個表:MS SQL服務器交叉表約束

1)應用(的AppId,名稱)
2)屏幕(ScreenId,名稱)
3)關係式(的AppId,ScreenId)

現在我想對相關表應用一些限制: 可以將同一個屏幕分配給多個應用程序,但不能有兩個同名分配給相同應用程序的屏幕。

我知道我可以將Screen.Name添加到關係表中,然後在AppId和Screen.Name上創建PK,但我不想要這樣的解決方案,因爲Screen.Name可能會更改。

我有什麼額外的選擇來實現這種限制?

回答

8

您可以創建基於RelationScreen表的indexed view和應用的唯一約束存在。

create view DRI_UniqueScreens 
with SCHEMABINDING 
as 
    select r.AppId,s.Name 
    from 
     [Schema].Relation r 
     inner join 
     [Schema].Screen s 
     on 
      r.ScreenId = s.ScreenId 
GO 
CREATE UNIQUE CLUSTERED INDEX IX_DRI_UniqueScreens 
    on DRI_UniqueScreens (AppId,Name) 
+0

我想知道是否有這樣的事情。 :)比觸發器好得多。 :) – Jonathan 2013-05-01 07:46:26

+0

更改屏幕名稱時,此方法會「驗證」數據,還是僅在訪問視圖時檢查數據? – 2013-05-01 07:59:17

+2

@AlexDn - 是的,這將強制在基礎表中進行更改時執行約束。如果你轉到我鏈接的頁面,你會注意到索引視圖有很多限制。這些限制中的大多數存在*,因爲它們允許以有效的方式在基表中的每個事務上發生所需的維護活動。 – 2013-05-01 08:09:58

0

這不是一個好的解決方案,但是您可以添加觸發器到屏幕和關係表中,只檢查您修改的內容是否符合您的條件,如果不是,則回滾。

CREATE TRIGGER trgScreen ON Screen FOR INSERT, UPDATE 
AS 
BEGIN 
    IF EXISTS (SELECT r.AppID, s.Name FROM Screen s 
       INNER JOIN Relation r ON s.ScreenID = r.ScreenID 
       GROUP BY r.AppID, s.Name 
       HAVING count(*) > 1) 
     ROLLBACK TRANSACTION 
END 

CREATE TRIGGER trgRelation ON Relation FOR INSERT, UPDATE 
AS 
BEGIN 
    IF EXISTS (SELECT r.AppID, s.Name FROM Screen s 
       INNER JOIN Relation r ON s.ScreenID = r.ScreenID 
       GROUP BY r.AppID, s.Name 
       HAVING count(*) > 1) 
     ROLLBACK TRANSACTION 
END 
+0

是的,觸發器將工作,但我儘量避免觸發器。 – 2013-05-01 08:00:00