MS SQL服务器交叉表约束

问题描述:

我有三个表:MS SQL服务器交叉表约束

1)应用(的AppId,名称)
2)屏幕(ScreenId,名称)
3)关系式(的AppId,ScreenId)

现在我想对相关表应用一些限制: 可以将同一个屏幕分配给多个应用程序,但不能有两个同名分配给相同应用程序的屏幕。

我知道我可以将Screen.Name添加到关系表中,然后在AppId和Screen.Name上创建PK,但我不想要这样的解决方案,因为Screen.Name可能会更改。

我有什么额外的选择来实现这种限制?

您可以创建基于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

这不是一个好的解决方案,但是您可以添加触发器到屏幕和关系表中,只检查您修改的内容是否符合您的条件,如果不是,则回滚。

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