編集:私が禁止しようとしているサンプルデータに追加されました。
この質問はこれに似ています:同じテーブルを 2 回参照しているため、View に CLUSTERED INDEX を作成できません。回避策はありますか? しかし、そこにある答えは私を助けません。私は一意性を強制しようとしているので、代替手段なしで「それをしないでください」という答えは、私の進歩に役立ちません.
問題の例 (簡略化):
CREATE TABLE [dbo].[Object]
(
Id INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
OrgId UNIQUEIDENTIFIER
)
CREATE TABLE [dbo].[Attribute]
(
Id INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
Name NVARCHAR(256) NOT NULL
)
CREATE TABLE [dbo].[ObjectAttribute]
(
Id INT NOT NULL IDENTITY(1, 1),
ObjectId INT NOT NULL,
AttributeId INT NOT NULL,
Value NVARCHAR(MAX) NOT NULL,
CONSTRAINT FK_ObjectAttribute_Object FOREIGN KEY (ObjectId) REFERENCES [Object] (Id),
CONSTRAINT FK_ObjectAttribute_Attribute FOREIGN KEY (AttributeId) REFERENCES Attribute (Id)
)
GO
CREATE UNIQUE INDEX IUX_ObjectAttribute ON [dbo].[ObjectAttribute] ([ObjectId], [AttributeId])
GO
CREATE VIEW vObject_Uniqueness
WITH SCHEMABINDING
AS
SELECT
ObjectBase.OrgId
, CAST(OwnerValue.Value AS NVARCHAR(256)) AS OwnerValue
, CAST(NameValue.Value AS NVARCHAR(50)) AS NameValue
FROM [dbo].[Object] ObjectBase
INNER JOIN [dbo].ObjectAttribute OwnerValue
INNER JOIN [dbo].Attribute OwnerAttribute
ON OwnerAttribute.Id = OwnerValue.AttributeId
AND OwnerAttribute.Name = 'Owner'
ON OwnerValue.ObjectId = ObjectBase.Id
INNER JOIN [dbo].ObjectAttribute NameValue
INNER JOIN [dbo].Attribute NameAttribute
ON NameAttribute.Id = NameValue.AttributeId
AND NameAttribute.Name = 'Name'
ON NameValue.ObjectId = ObjectBase.Id
GO
/*
Cannot create index on view "[Database].dbo.vObject_Uniqueness". The view contains a self join on "[Database].dbo.ObjectAttribute".
*/
CREATE UNIQUE CLUSTERED INDEX IUX_vObject_Uniqueness
ON vObject_Uniqueness (OrgId, OwnerValue, NameValue)
GO
DECLARE @Org1 UNIQUEIDENTIFIER = NEWID();
DECLARE @Org2 UNIQUEIDENTIFIER = NEWID();
INSERT [dbo].[Object]
(
OrgId
)
VALUES
(@Org1) -- Id: 1
, (@Org2) -- Id: 2
, (@Org1) -- Id: 3
INSERT [dbo].[Attribute]
(
Name
)
VALUES
('Owner') -- Id: 1
, ('Name') -- Id: 2
--, ('Others')
-- Acceptable data.
INSERT [dbo].[ObjectAttribute]
(
AttributeId
, ObjectId
, Value
)
VALUES
(1, 1, 'Jeremy Pridemore') -- Owner for object 1 (Org1).
, (2, 1, 'Apple') -- Name for object 1 (Org1).
, (1, 2, 'John Doe') -- Owner for object 2 (Org2).
, (2, 2, 'Pear') -- Name for object 2 (Org2).
-- Unacceptable data.
-- Org1 already has an abject with an owner value of 'Jeremy' and a name of 'Apple'
INSERT [dbo].[ObjectAttribute]
(
AttributeId
, ObjectId
, Value
)
VALUES
(1, 3, 'Jeremy Pridemore') -- Owner for object 3 (Org1).
, (2, 3, 'Apple') -- Name for object 3 (Org1).
-- This is the bad data. I want to disallow this.
SELECT
OrgId, OwnerValue, NameValue
FROM vObject_Uniqueness
GROUP BY OrgId, OwnerValue, NameValue
HAVING COUNT(*) > 1
DROP VIEW vObject_Uniqueness
DROP TABLE ObjectAttribute
DROP TABLE Attribute
DROP TABLE [Object]
この例では、次のエラーが発生します。
Msg 1947, Level 16, State 1, Line 2
Cannot create index on view "TestDb.dbo.vObject_Uniqueness". The view contains a self join on "TestDb.dbo.ObjectAttribute".
これが示すように、2 つのテーブルを持つ属性システムを使用して、1 つのオブジェクトとその値を表しています。オブジェクトの存在とオブジェクトの OrgId はメイン テーブルにあり、残りの値はセカンダリ テーブルの属性です。
まず第一に、なぜこれが自己結合があると言っているのか理解できません。Object
からObjectAttribute
2回参加しています。ON
いいえ、句内のテーブルから同じテーブルに移動する場所はありません。
第二に、これを機能させる方法はありますか?または、私が行っている独自性を強制する方法はありますか? 私が望む最終結果は、によって、同じ「所有者」と「名前」の値を提供するそれらを参照するレコードを持つObject.OrgId
2つのObject
行がないことです。ObjectAttribute
そのため、OrgId、Owner、および Name の値は、任意の に対して一意である必要がありますObject
。