让我设置场景;
我必须与一个系统交谈,其中将两种类型的用户。在不详细说明的情况下,我们称之为超级用户和普通用户。
超级用户可能存在也可能不存在,但如果存在,则始终引用普通用户。普通用户总是存在,但可能是"软"删除。
系统上正在进行升级步骤。所有超级用户的普通用户都会获得一个新的超级用户帐户。任何软删除的普通用户都不能拥有超级用户帐户,即使他们之前有过。
我有两个表,Message和ReceivedMessage。
消息包含OnBehalfOfNormalUserId和消息内容。 ReceivedMessage包含发送消息的人的SuperUserId。
create table Message(MessageId int identity(1, 1) not null, OnBehalfOfNormalUserId int not null, Subject varchar(50) null, Content varchar(max) not null, constraint PK_MESSAGEID primary key (MessageId), contraint FK_ONBEHALFOFNORMALUSERID (OnBehalfOfNormalUserId) references User (UserId));
create table ReceivedMessage(QueueId int not null, MessageId int not null, SentBySuperUserId int null, constraint PK_QUEUEID primary key (QueueId), constraint FK_QUEUEID (QueueId) references MessageQueue (QueueId), constraint FK_SENTBYSUPERUSERID (SentBySuperUserId) references SuperUser (UserId));
这些表包含的内容不止这些,但这应该足以满足我的示例
现在,旧的系统可能已经由 超级用户的人发送了一条消息,但现在软件被删除且无法成为超级用户。这是通过放置" null"在" SentBySuperUserId"柱。但是,除非已经软删除了NormalUser,否则此列必须包含SuperUserId。在迁移后被软删除的任何NormalUser帐户将保留其超级用户帐户,但无法访问。 (我无法控制此过程或哪些数据不会被迁移)
User表有一个标记" IsDeleted"。如果标记了这个,则允许SentBySuperUserId为null,否则不允许。 (超级用户通过桥接表映射到NormalUser)
我创建了一个简单的View,返回任何NormalUserId,其中SuperUserId为null且User.IsDeleted = 0.但是,这对于索引视图来说已经足够了,因为单个消息将是" ok"就一个独特的约束而言。鉴于我不能进行子查询,我不能使用CTE而且我不能使用外连接,我不确定如何强制执行确保视图正好返回0行的约束。
答案 0 :(得分:0)
如何对确保0行的视图强制执行约束 在MSSQL中返回?
您不能,您可以在视图上应用的唯一约束类型是唯一约束,并且不可能使用单行突破该约束。
但是,您总是可以将结果加倍,以便它确实违反约束,并且您可以声明性地强制执行此操作。
您需要创建一个表并插入两行。
将CROSS JOIN dbo.TwoRows
添加到您的视图定义中,并在其上创建唯一索引。
现在,从原始查询返回的每一行都会加倍。因此,如果原始查询返回任何行,它将违反其上的唯一索引。
能够交叉连接到包含两行的虚拟表会更好,但在索引视图中不允许派生表等。
注意:对于我来说,它确实可能会定义视图,以便在尝试实现甚至单行(例如除以零)时导致运行时错误,但这是更多可怕的解决方案,也不能保证工作,因为表达可以在计划的一部分进行评估,然后才能被过滤掉。