所以我有两张桌子:
Requests
--------
Id
RequestSchemeId
ReceivedByUserId
ForwardedRequests
-----------------
Id
RequestId (FK to Id column of Requests Table)
ForwardedToUserId
和一个视图
ForwardedRequestsInRequestSchemes
---------------------------------
Requests.RequestSchemeId
Requests.ReceivedByUserId
ForwardedRequests.ForwardedToUserId
在视图中向Requests.ReceivedByUserId != ForwardedRequests.ForwardedToUserId
添加约束等效的标准/推荐方法是什么?
我知道视图中不允许检查约束。使用SQL Server 2008。
编辑:
这是this question的后续问题。
业务规则:
可以将同一请求转发给多个用户。因此ForwardedRequests表中的Id列。
用户只能收到特定RequestScheme的一个请求。所以我在Requests表中为RequestSchemeId + ReceivedByUserId创建了一个UniqueKey约束。
只有当转发用户在任何其他用户的同一方案下没有转发请求时,才能将请求转发给其他用户。正如Martin在linked question中建议的那样,我从两个表创建了一个视图,并在Requests.RequestSchemeId + ForwardedRequests.ForwardedToUserId上添加了一个唯一约束。
这个问题涉及的业务规则是,请求的接收者不能将其转发给他/她自己。
答案 0 :(得分:9)
我可以想到让SQL Server为您强制执行此操作的几种方法。虽然对看到任何其他方法感兴趣,但两者都非常讨厌。
1)您可以在索引视图ForwardedRequestsInRequestSchemes
中添加一个额外的列1/(ForwardedToUserId - ReceivedByUserId) AS FailIfSame
,如果这两个值相同,则会引发Divide by zero error
。这确实意味着您最终会在索引视图中存储冗余列。
2)您可以创建一个新视图,将任何此类行交叉连接到两行表上,然后在该视图上定义唯一约束。此视图将始终为空。
CREATE TABLE dbo.TwoRows(C INT) INSERT INTO dbo.TwoRows VALUES(1),(1)
GO
CREATE VIEW dbo.FailIfForwardedUserEqualToReceivedByUser
WITH SCHEMABINDING
AS
SELECT 1 AS C
FROM dbo.ForwardedRequests FR
INNER JOIN dbo.Requests R
ON R.Id = FR.RequestId AND R.ReceivedByUserId = FR.ForwardedToUserId
CROSS JOIN dbo.TwoRows
GO
CREATE UNIQUE CLUSTERED INDEX ix ON
dbo.FailIfForwardedUserEqualToReceivedByUser(C)
答案 1 :(得分:2)
一种方法是禁止表上的update, insert, delete
权限,并使用存储过程强制执行业务需求。例如,
create procedure dbo.AddRequestForward(
@requestId int
, @forwardedToUserId int)
as
insert ForwardedRequests
(ForwardedRequests, ForwardedRequests)
select @requestId
, @forwardedToUserId
where not exists
(
select *
from Requests
where Id = @requestId
and @forwardedToUserId = @forwardedToUserId
)
if @@rowcount = 0
return -1 -- Forwarded and Received identical user
return 1 -- Success
go