SQL Server唯一索引跨表

前端之家收集整理的这篇文章主要介绍了SQL Server唯一索引跨表前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
可以在表之间创建唯一的索引,基本上使用视图和唯一索引.

我有一个问题.

给定两(或三)表.

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而失败了

我如何解决这种情况?

品牌/产品的基本代码不能在公司内重复.

笔记:

我得到的错误是:

Msg 10116,Level 16,State 1,Line 3 Cannot create index on view
‘XXXX.dbo.TestView’ because it contains one or more UNION,INTERSECT,
or EXCEPT operators. Consider creating a separate indexed view for
each query that is an input to the UNION,or EXCEPT
operators of the original view.

备注2:

当我使用子查询我得到以下错误

Msg 10109,Line 3 Cannot create index on view
“XXXX.dbo.TestView” because it references derived table “a”
(defined by SELECT statement in FROM clause). Consider removing the
reference to the derived table or not indexing the view.

**注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,'Brand 4',400 ),(5,'Brand 5',500 )

INSERT INTO Product
(
    Id,BrandId,Code
)
VALUES
(1001,'Product 1001',1 ),(1002,'Product 1002',2 ),(1003,'Product 1003',3 ),(1004,'Product 1004',301 ),(1005,4,'Product 1005',5 )

期望的是,如果我们扩大结果,品牌代码公司或产品代码公司是独一无二的.

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,Code
)
VALUES 
(6,'Brand 6',999)

INSERT INTO Product
(
    Id,Code
)
VALUES
(1006,'Product 1006',999)

该产品属于不同的公司,所以我们得到

Company / Brand|Product Code
1 / 999 <-- Brand
2 / 999 <-- Product

这是独一无二的.

但如果你有2个品牌,和1个产品.

INSERT INTO Brand
(
    Id,Code
)
VALUES 
(7,'Brand 7',777)
(8,'Brand 8',888)

INSERT INTO Product
(
    Id,Code
)
VALUES
(1007,8,'Product 1008',777)

这会产生

Company / Brand|Product Code
1 / 777 <-- Brand
1 / 888 <-- Brand
1 / 777 <-- Product

这是不允许的.

希望是有道理的.

备注4:

@ spaghettidba的答案解决了跨表问题,第二个问题在品牌表本身中重复.

我已经设法通过在品牌表上创建一个单独的索引来解决这个问题:

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,Code int
)
GO

INSERT INTO Brand
(
    Id,Code
)
VALUES (1,500 )



INSERT INTO Product
(
    Id,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,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.

希望这可以帮助.

猜你在找的MsSQL相关文章