正确的方式来实施这种一对一的关系

时间:2013-12-29 10:04:05

标签: sql sql-server database-design relational-database

TableATableBTableC都需要TableX中的一行,但不能在表格的多行之间共享一行TableX AC。 (表A-C完全不同)。

我可以想到一些解决方案,但哪一个(如果有的话)是正确的?

选项1

将TableX上的字段展平到表A-C上(我最不喜欢的选项)。


选项2

这实际上看起来像是一对一的链接,但最容易在数据库中以一对一的方式强制执行。使用实体框架不能很好地工作。

表A-C

[Id] IDENTITY INT NOT NULL,
[TableAId] INT NULL,
[TableBId] INT NULL,
[TableCId] INT NULL,

CONSTRAINT [PK_TableX] PRIMARY KEY,
CONSTRAINT [FK_TableX_TableA] FOREIGN KEY [TableAId] REFERENCES [TableA]([Id]),
CONSTRAINT [FK_TableX_TableB] FOREIGN KEY [TableBId] REFERENCES [TableB]([Id]),
CONSTRAINT [FK_TableX_TableC] FOREIGN KEY [TableCId] REFERENCES [TableC]([Id]),    
CONSTRAINT [UQ_TableX_TableAId] UNIQUE ([TableAId]),
CONSTRAINT [UQ_TableX_TableBId] UNIQUE ([TableBId]),
CONSTRAINT [UQ_TableX_TableCId] UNIQUE ([TableCId]),
CONSTRAINT [CK_TableX_Owner] CHECK
(
    ([TableAId] IS NOT NULL AND [TableBId] IS NULL AND [TableCId] IS NULL) OR
    ([TableBId] IS NOT NULL AND [TableCId] IS NULL AND [TableAId] IS NULL) OR
    ([TableCId] IS NOT NULL AND [TableAId] IS NULL AND [TableBId] IS NULL)
)

TableX的

[Id] IDENTITY INT NOT NULL

选项3

这是我最喜欢的选项,因为它似乎代表最佳的一对一链接(因为我们不能使Id TableX与表AC的主键匹配。 ORM(在本例中为Entity Framework)将处理其余部分。

表A-C

[Id] IDENTITY INT NOT NULL,
[TableXId] INT NOT NULL,

CONSTRAINT [PK_Table*] PRIMARY KEY,
CONSTRAINT [FK_Table*_TableX] FOREIGN KEY [TableXId] REFERENCES [TableX]([Id]) ON DELETE CASCADE
CONSTRAINT [UQ_Table*_TableXId] UNIQUE ([TableXId])

TableX的

Id IDENTITY INT NOT NULL,

CONSTRAINT [PK_TableX] PRIMARY KEY

3 个答案:

答案 0 :(得分:0)

选项4:

dbo.TableX

Id IDENTITY INT NOT NULL,
CONSTRAINT [PK_TableX] PRIMARY KEY,
Type CHAR(1) NOT NULL,
CONSTRAINT CK_TableX_VerifyType CHECK( Type IN ('A', 'B', 'C') ),
CONSTRAINT UQ_TableX_Id_Type UNIQUE (Id, Type)

dbo.Table {A | B | C}

[TableXId] INT NOT NULL,
CONSTRAINT [PK_Table*] PRIMARY KEY (TableXId),
CONSTRAINT [FK_Table*_TableX_TableXId] FOREIGN KEY ([TableXId]) REFERENCES [TableX]([Id]) ON DELETE CASCADE,
Type CHAR(1) NOT NULL,
CONSTRAINT CK_Table*_VerifyType CHECK( Type = 'A' ) -- For dbo.TableA or ='B' for dbo.TableB or ...
CONSTRAINT [FK_Table*_TableX_TableXId_Type] FOREIGN KEY ([TableXId], Type) REFERENCES [TableX]([Id], Type) ON DELETE CASCADE,

答案 1 :(得分:0)

这不是严格意义上的一对一"关系。这实际上是一组3"一个为零或一个"与"排他性" 的附加条件的关系(表A,B和C不能在X中共享一行)和"存在" (X中的一行不能没有A,B或C中的行。)

  • 在支持延迟外键的DBMS上,可以声明性地强制执行排他性和在线状态。
  • 在没有 1 的DBMS上,只能以声明方式强制执行排他性,并且必须从应用程序代码强制执行。

有关如何实际执行此操作的说明,请参阅:Supertype-subtype database design


1 不幸的是,MS SQL Server属于该类别。

答案 2 :(得分:0)

您可以在A,B和C

上创建索引视图
create view myView as 

   select xId from tableA
   union all
   select xId from tableB
   union all
   select xId from tableC

go

create unique clustered index [CIX_myView] on dbo.myView (xId)