基本上可以使用视图和唯一索引在整个表之间创建唯一索引。
我有一个问题。
给定两个(或三个)表。
Company
- Id
- Name
Brand
- Id
- CompanyId
- Name
- Code
Product
- Id
- BrandId
- Name
- Code
我想确保以下各项的唯一性:
Company / Brand.Code
和
Company / Brand.Product/Code
是独一无二的
CREATE VIEW TestView
WITH SCHEMABINDING
AS
SELECT b.CompanyId, b.Code
FROM dbo.Brand b
UNION ALL
SELECT b.CompanyId, p.Code
FROM dbo.Product p
INNER JOIN dbo.Brand b ON p.BrandId = b.BrandId
视图的创建成功。
CREATE UNIQUE CLUSTERED INDEX UIX_UniquePrefixCode
ON TestView(CompanyId, Code)
之所以失败是因为 UNION
我该如何解决这种情况?
基本上,两者的代码都Brand/Product
不能在公司内重复。
笔记:
我得到的错误是:
消息10116,级别16,状态1,行3无法在视图“ XXXX.dbo.TestView”上创建索引,因为它包含一个或多个UNION,INTERSECT或EXCEPT运算符。考虑为每个查询创建一个单独的索引视图,这是原始视图的UNION,INTERSECT或EXCEPT运算符的输入。
注2:
当我使用子查询时,出现以下错误:
消息10109,级别16,状态1,行3无法在视图“ XXXX.dbo.TestView”上创建索引,因为它引用了派生表“ a”(由FROM子句中的SELECT语句定义)。考虑删除对派生表的引用,或者不对视图建立索引。
**注3:**
因此,鉴于品牌:
从@spaghettidba的答案。
INSERT INTO Brand
(
Id,
CompanyId,
Name,
Code
)
VALUES
(1, 1, 'Brand 1', 100 ),
(2, 2, 'Brand 2', 200 ),
(3, 3, 'Brand 3', 300 ),
(4, 1, 'Brand 4', 400 ),
(5, 3, 'Brand 5', 500 )
INSERT INTO Product
(
Id,
BrandId,
Name,
Code
)
VALUES
(1001, 1, 'Product 1001', 1 ),
(1002, 1, 'Product 1002', 2 ),
(1003, 3, 'Product 1003', 3 ),
(1004, 3, 'Product 1004', 301 ),
(1005, 4, 'Product 1005', 5 )
如果我们扩展结果,则期望是Brand Code + Company
或Product Code + Company
唯一。
Company / Brand|Product Code
1 / 100 <-- Brand
1 / 400 <-- Brand
1 / 1 <-- Product
1 / 2 <-- Product
1 / 5 <-- Product
2 / 200 <-- Brand
3 / 300 <-- Brand
3 / 500 <-- Brand
3 / 3 <-- Product
3 / 301 <-- Brand
没有重复。如果我们的品牌和产品具有相同的代码。
INSERT INTO Brand
(
Id,
CompanyId,
Name,
Code
)
VALUES
(6, 1, 'Brand 6', 999)
INSERT INTO Product
(
Id,
BrandId,
Name,
Code
)
VALUES
(1006, 2, 'Product 1006', 999)
该产品属于其他公司,因此我们得到
Company / Brand|Product Code
1 / 999 <-- Brand
2 / 999 <-- Product
这是独一无二的。
但是,如果您有2个品牌和1个产品。
INSERT INTO Brand
(
Id,
CompanyId,
Name,
Code
)
VALUES
(7, 1, 'Brand 7', 777)
(8, 1, 'Brand 8', 888)
INSERT INTO Product
(
Id,
BrandId,
Name,
Code
)
VALUES
(1007, 8, 'Product 1008', 777)
这会产生
Company / Brand|Product Code
1 / 777 <-- Brand
1 / 888 <-- Brand
1 / 777 <-- Product
这是不允许的。
希望有道理。
注4:
@spaghettidba的答案解决了跨表问题,第二个问题是Brand表本身中的重复项。
我设法通过在brand表上创建单独的索引来解决此问题:
CREATE UNIQUE NONCLUSTERED INDEX UIX_UniquePrefixCode23
ON Brand(CompanyId, Code)
WHERE Code IS NOT NULL;
我在2011年就发布了类似解决方案的博客。您可以在此处找到该帖子:http : //spaghettidba.com/2011/08/03/enforcing-complex-constraints-with-indexed-views/
基本上,您必须创建一个表,该表恰好包含两行,并且您将在CROSS JOIN中使用该表来复制违反业务规则的行。
在您的情况下,由于您表达业务规则的方式,索引视图很难编码。实际上,正如您已经看到的那样,不允许通过索引视图检查UNIONed表的唯一性。
但是,约束可以用不同的方式表示:由于品牌暗示了companyId,因此可以避免UNION,而只需在产品和品牌之间使用JOIN并通过在代码本身上添加JOIN谓词来检查唯一性。
您没有提供一些示例数据,希望您不介意我帮您做一下:
CREATE TABLE Company (
Id int PRIMARY KEY,
Name varchar(50)
)
CREATE TABLE Brand (
Id int PRIMARY KEY,
CompanyId int,
Name varchar(50),
Code int
)
CREATE TABLE Product (
Id int PRIMARY KEY,
BrandId int,
Name varchar(50),
Code int
)
GO
INSERT INTO Brand
(
Id,
CompanyId,
Name,
Code
)
VALUES (1, 1, 'Brand 1', 100 ),
(2, 2, 'Brand 2', 200 ),
(3, 3, 'Brand 3', 300 ),
(4, 1, 'Brand 4', 400 ),
(5, 3, 'Brand 5', 500 )
INSERT INTO Product
(
Id,
BrandId,
Name,
Code
)
VALUES
(1001, 1, 'Product 1001', 1 ),
(1002, 1, 'Product 1002', 2 ),
(1003, 3, 'Product 1003', 3 ),
(1004, 3, 'Product 1004', 301 ),
(1005, 4, 'Product 1005', 5 )
据我所知,目前还没有违反业务规则的行。
现在我们需要索引视图和两行表:
CREATE TABLE tworows (
n int
)
INSERT INTO tworows values (1),(2)
GO
这是索引视图:
CREATE VIEW TestView
WITH SCHEMABINDING
AS
SELECT 1 AS one
FROM dbo.Brand b
INNER JOIN dbo.Product p
ON p.BrandId = b.Id
AND p.code = b.code
CROSS JOIN dbo.tworows AS t
GO
CREATE UNIQUE CLUSTERED INDEX IX_TestView ON dbo.TestView(one)
此更新应打破业务规则:
UPDATE product SET code = 300 WHERE code = 301
实际上,您会得到一个错误:
Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.TestView' with unique index 'IX_TestView'. The duplicate key value is (1).
The statement has been terminated.
希望这可以帮助。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句