假设我有一些可能会或可能不会 或与 Bravo或Charlie事物有关的Alpha事件。
这些是一对一的关系:没有Alpha会涉及多个Bravo。并且Bravo不会涉及多个Alpha。
我有几个目标:
我有三个想法......
PK = primary key
FK = foreign key
NU = nullable
一张包含许多nullalbe字段的表格(平面文件)......
Alphas
--------
PK AlphaId
AlphaOne
AlphaTwo
AlphaThree
NU BravoOne
NU BravoTwo
NU BravoThree
NU CharlieOne
NU CharlieTwo
NU CharlieThree
许多没有nullalbe字段的表......
Alphas
--------
PK AlphaId
AlphaOne
AlphaTwo
AlphaThree
Bravos
--------
FK PK AlphaId
BravoOne
BravoTwo
BravoThree
Charlies
--------
FK PK AlphaId
CharlieOne
CharlieTwo
CharlieThree
两者中最好的(或最差的):许多表中的许多nullalbe外键......
Alphas
--------
PK AlphaId
AlphaOne
AlphaTwo
AlphaThree
NU FK BravoId
NU FK CharlieId
Bravos
--------
PK BravoId
BravoOne
BravoTwo
BravoThree
Charlies
--------
PK CharlieId
CharlieOne
CharlieTwo
CharlieThree
如果Alpha必须是Bravo或Charlie,而不是两者都是怎么办?
如果不仅仅是Bravos和Charlies,Alphas也可能是Deltas,Echos,Foxtrots或Golfs等......?
编辑:这是问题的一部分:Which is the best database schema for my navigation?
答案 0 :(得分:8)
如果您希望每个Alpha只与一个Bravo相关,我会使用组合的FK / PK投票支持这种可能性:
Bravos
--------
FK PK AlphaId
BravoOne
BravoTwo
BravoThree
这样,只有一个Bravo可能会引用你的Alphas。
如果Bravos和Charlies必须互相排斥,最简单的方法可能是创建一个鉴别器字段:
Alpha
--------
PK AlphaId
PK AlphaType NOT NULL IN ("Bravo", "Charlie")
AlphaOne
AlphaTwo
AlphaThree
Bravos
--------
FK PK AlphaId
FK PK AlphaType == "Bravo"
BravoOne
BravoTwo
BravoThree
Charlies
--------
FK PK AlphaId
FK PK AlphaType == "Charlie"
CharlieOne
CharlieTwo
CharlieThree
这样,AlphaType字段强制记录始终属于一个子类型。
答案 1 :(得分:4)
我假设您将使用SQL Server 2000/2005。我使用的是一对一关系的标准模式,这与您的第二个想法并不太相似,但这里有不同之处:< / p>
每个实体必须首先拥有自己的主键,因此除了Alpha表的外键列之外,您的Bravo,Charlie等表应定义自己的代理键。通过指定一个表的主键必须与另一个表的主键完全相同,您的域模型非常不灵活。因此,实体变得紧密耦合,一个实体在没有另一个实体的情况下不能存在,这不是需要在数据库设计中强制执行的业务规则。
将Bravo和Charlie表中的AlphaID列之间的外键约束添加到Alpha表的主键列。这为您提供了1对多,并且还允许您仅通过设置FK列的可为空性来指定关系是否是强制性的(这是您当前设计中无法实现的)。
在AlphaID列上为表格Bravo,Charlie等添加唯一键约束。这将创建一对一的关系,并且附加的好处是唯一键还可以充当索引,可以帮助加快基于外键值检索行的查询。
这种方法的主要好处是变化更容易:
答案 2 :(得分:3)
就我个人而言,我在第二个模型上取得了很大的成功,在一个列上使用PK / FK。
我从未遇到过所有Alpha都要求在Bravo或Charlie表中记录的情况。我总是处理1&lt; - &gt; 0..1,从不1&lt; - &gt; 1。
关于你的上一个问题,那就是更多的表格。
答案 3 :(得分:1)
另一种方法是使用3个表来存储3个实体,并有一个单独的表来存储关系。
答案 4 :(得分:1)
您可以拥有一个指定Alpha和相关ID的连接表。然后,您可以添加另一列,指定它是否为Bravo,Charlie或其他任何内容的ID。保持Alpha列上的蠕变,但确实增加了加入查询的复杂性。
答案 5 :(得分:1)
到目前为止,我有一个很好的例子适合你的模型:
我有来自Alpha的外键alpha_id的Charlie和Bravo表。与您的第一个示例一样,除了alpha不是主键,bravo_id和charlie_id都是。
我在每个需要解决这些实体的表上使用alpha_id,因此,为了避免可能导致某些延迟研究Bravo和Charlie找到哪一个Alpha的SQL,我创建了一个AlphaType表并在Alpha表I上将其id(alpha_type_id)作为外键。这样我就能以程序化的方式知道我正在处理哪个AlphaType而没有连接可能有数万个记录的表。在tSQL中:
// For example sake lets think Id as a CHAR.
// and pardon me on any mistake, I dont have the exact code here,
// but you can get the idea
SELECT
(CASE alpha_type_id
WHEN 'B' THEN '[Bravo].[Name]'
WHEN 'C' THEN '[Charlie].[Name]'
ELSE Null
END)
FROM ...
答案 6 :(得分:1)
您提出了许多问题,这些问题很难选择您提出的任何解决方案,而无需对您要解决的确切问题进行更多说明。不仅要考虑我的澄清问题,还要考虑用于评估我的问题的标准,作为解决问题所需详细信息量的指示:
什么“系统”易于学习和维护?您的应用的源代码,或通过其最终用户界面的应用程序数据?
“在我的数据库中执行”是什么意思?这是否意味着您无法通过任何其他方式控制数据完整性,即项目只需要基于数据库的数据完整性规则?
您能为我们提供您所指的现实世界,逻辑组织吗?从您试图存储的三个数据示例中推断它是不可能的 - 即假设您的所有三个结构都完全错误。除非我们知道现实世界的规范,否则我们怎么知道?
这个要求听起来像你的手被迫使用linq to SQL创建这个,是这样吗?
什么是“快速”? .03秒? 3秒? 30分钟?目前还不清楚,因为您没有指定要引用的操作的数据大小和类型。
空间的有效使用与空字段的数量无关。如果您的意思是规范化的数据库结构,那将再次依赖于问题中未提供的实际规范和应用程序的其他设计元素。
答案 7 :(得分:0)
除非我有充分的理由不这样做,否则我会选择选项1。它可能不会像你想象的那样花费你太多的空间,尤其是如果您在Bravo中使用varchars。不要忘记拆分它将花费你的外键,辅助身份和所需的索引。
您可能遇到麻烦的地方是不太可能需要Bravo(&lt;%10)并且您需要快速查询其中一个字段以便对其进行索引。
答案 8 :(得分:0)
我会创建一个超类型/子类型关系。
THINGS
------
PK ThingId
ALPHAS
------
FK ThingId (not null, identifying, exported from THINGS)
AlphaCol1
AlphaCol2
AlphaCol3
BRAVOS
------
FK ThingId (not null, identifying, exported from THINGS)
BravoCol1
BravoCol2
BravoCol3
CHARLIES
--------
FK ThingId (not null, identifying, exported from THINGS)
CharlieCol1
CharlieCol2
CharlieCol3
因此,例如,一个有查理而不是一个查理的阿尔法: -
insert into things values (1);
insert into alphas values (1,'alpha col 1',5,'blue');
insert into charlies values (1,'charlie col 1',17,'Y');
注意,您不能为alpha创建多个charlie,就好像您尝试使用ThingId为1创建两个charlies,第二个插入将获得唯一的索引/约束违规。