想象一下,我有以下结构:
DECLARE @Products TABLE (
MemberId INT,
ProductId INT,
GlobalProductId INT,
PRIMARY KEY (MemberId, ProductId));
INSERT INTO @Products VALUES (1, 1, NULL);--this is my "global product"
INSERT INTO @Products VALUES (2, 1, NULL);--this is okay
INSERT INTO @Products VALUES (2, 2, 1);--this is okay
INSERT INTO @Products VALUES (2, 3, 2);--this should fail
SELECT * FROM @Products;
我想强制执行的规则是,MemberId = 1持有全球产品,而所有其他MemberId持有普通产品。一组普通产品可以链接到一个全球产品。
所以我希望会员的产品能够链接到全局产品,即存在外键约束,如果GlobalProductId不为NULL,则应该存在与GlobalProductId匹配的ProductId,其中MemberId = 1。
在上面的示例中,我有一个ProductId = 1的全局产品。然后我创建了三个普通产品:
第三个应该失败,因为我已将其链接到不存在的全局产品,即此脚本将不返回任何内容:
SELECT * FROM @Products WHERE MemberId = 1 AND ProductId = 2;
我可以看到,最简单的解决方案是创建一个新表,只保留全球产品。这种方法的问题在于我有一整套例程来加载,更新,删除Product表中的数据,以及第二组例程来执行同一个表中的计算等。如果我要介绍一个新的“全局产品”表,那么我将不得不复制几十个UDF来实现这一点,我的代码将变得更加复杂。
答案 0 :(得分:2)
添加一个固定为1
的计算列,然后添加一个外键:
CREATE TABLE Products (
MemberId INT,
ProductId INT,
GlobalProductId INT,
PRIMARY KEY (MemberId, ProductId),
GlobalMemberId AS 1 PERSISTED,
FOREIGN KEY (GlobalMemberId,GlobalProductID)
references Products (MemberId,ProductID)
);
INSERT INTO Products VALUES (1, 1, NULL);--this is my "global product"
INSERT INTO Products VALUES (2, 1, NULL);--this is okay
INSERT INTO Products VALUES (2, 2, 1);--this is okay
INSERT INTO Products VALUES (2, 3, 2);--this should fail
SELECT * FROM Products;
这会产生以下结果:
Msg 547,Level 16,State 0,Line 1
INSERT语句与FOREIGN KEY SAME TABLE约束“
FK__Products__7775B2CE
”冲突。冲突发生在数据库“abc
”,表“dbo.Products
”。声明已经终止。
MemberId ProductId GlobalProductId GlobalMemberId
----------- ----------- --------------- --------------
1 1 NULL 1
2 1 NULL 1
2 2 1 1
答案 1 :(得分:0)
为什么不添加CHECK
约束:
ALTER TABLE Products ADD CONSTRAINT CHK_ColumnD_GlobalProductId
CHECK (GlobalProductId IS NULL AND MemberId = 1
OR GlobalProductId IS NOT NULL AND MemberId != 1);
和FOREIGN KEY
:
ALTER TABLE Products ADD CONSTRAINT fk_SelfProducts
FOREIGN KEY (GlobalProductId )
REFERENCES Products (ProductId)