Database 什么';在SQL中处理一对一关系的最佳方法是什么?
假设我有阿尔法的东西,可能与布拉沃或查理的东西有关,也可能与之无关 这是一对一的关系:没有阿尔法将涉及到一个以上的布拉沃。没有比一个阿尔法更重要的了 我有几个目标:Database 什么';在SQL中处理一对一关系的最佳方法是什么?,database,linq,linq-to-sql,database-design,schema,Database,Linq,Linq To Sql,Database Design,Schema,假设我有阿尔法的东西,可能与布拉沃或查理的东西有关,也可能与之无关 这是一对一的关系:没有阿尔法将涉及到一个以上的布拉沃。没有比一个阿尔法更重要的了 我有几个目标: 易于学习和使用的系统 维持 在我的 数据库 与 现实世界中的逻辑组织 我的数据 我的系统中的类/对象 很好地映射到 数据库表(从Linq到SQL) 快速读写操作 有效利用空间(很少有空字段) 我有三个想法 PK = primary key FK = foreign key NU = nullable 一个包含许多空字段
- 易于学习和使用的系统 维持
- 在我的 数据库
- 与 现实世界中的逻辑组织 我的数据
- 我的系统中的类/对象 很好地映射到 数据库表(从Linq到SQL)
- 快速读写操作
- 有效利用空间(很少有空字段)
PK = primary key
FK = foreign key
NU = nullable
一个包含许多空字段的表(平面文件)
许多具有零nullalbe字段的表
Alphas
--------
PK AlphaId
AlphaOne
AlphaTwo
AlphaThree
Bravos
--------
FK PK AlphaId
BravoOne
BravoTwo
BravoThree
Charlies
--------
FK PK AlphaId
CharlieOne
CharlieTwo
CharlieThree
两者中最好的(或最差的):许多表都有许多空外键
Alphas
--------
PK AlphaId
AlphaOne
AlphaTwo
AlphaThree
NU FK BravoId
NU FK CharlieId
Bravos
--------
PK BravoId
BravoOne
BravoTwo
BravoThree
Charlies
--------
PK CharlieId
CharlieOne
CharlieTwo
CharlieThree
如果阿尔法必须是布拉沃或查理,但不是两者都是呢
如果阿尔法也可以是三角洲、回声、狐步、高尔夫等等,而不仅仅是布拉沃和查理,那会怎么样
编辑:这是问题的一部分:另外一种方法是使用3个表来存储3个实体,并使用一个单独的表来存储关系。就我个人而言,我在您的第二个模型上取得了很大成功,在一列上使用PK/FK 我从来没有遇到过这样的情况:所有的阿尔法人都必须在布拉沃或查理表格中记录。我一直在处理10..1,从来没有处理过11
至于你的最后一个问题,那只是更多的表。你可以有一个连接表来指定Alpha和相关ID。然后你可以添加另一列,指定它是否是Bravo、Charlie或其他的ID。保持列在Alpha上向下移动,但确实增加了连接查询的复杂性。除非我有充分理由不这样做,否则我会选择选项1。它可能不会花费你想象的那么多空间,特别是如果你在布拉沃使用varchars。不要忘记,拆分它将花费外键、辅助标识和所需的索引。
如果不太可能需要Bravo,您可能会遇到麻烦(如果您希望每个Alpha只与一个Bravo相关,我会投票支持使用组合FK/PK的可能性:
Bravos
--------
FK PK AlphaId
BravoOne
BravoTwo
BravoThree
这样一来,只有一个Bravo可以引用你的Alpha
如果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字段强制记录始终只属于一个子类型。到目前为止,我有一个非常适合您的模型的示例: 我有Charlie和Bravo表,它们的外键alpha_id来自alpha。与第一个示例一样,除了alpha不是主键之外,Bravo_id和Charlie_id是主键 我在每个需要寻址到这些实体的表上都使用了alpha_id,因此,为了避免SQL可能会导致延迟研究Bravo和Charlie以找到哪一个alpha,我创建了一个AlphaType表,在alpha表上我有它的id(alpha_type_id)作为外键。这样我就可以通过编程的方式知道我在处理哪个字母类型,而不必连接可能有无数记录的表。在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 ...
我将创建一个超类型/子类型关系
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一样,第二次插入将得到唯一的索引/约束冲突。您提出了许多问题,如果不对您正在尝试的确切问题进行更多澄清,就很难选择任何建议的解决方案不要仅仅考虑我的澄清问题,而是考虑你用来评价我的问题的标准,来说明解决问题所需的细节量:
- 易于学习和维护的系统
- 在我的数据库中强制执行数据完整性
- 与数据的真实逻辑组织相匹配的架构
- 编程中映射到数据库表的类/对象(从Linq到SQL)
- 快速读写操作
- 有效利用空间(很少有空字段)
空间的有效使用与空字段的数量无关。如果您指的是规范化的数据库结构,那么这将再次取决于实际的规范和应用程序中未提供的其他设计元素。我假设您将使用SQL Server 2000/2005。我有一个标准模式对于我使用的1对1关系,这与你的第二个想法没有太大的不同,但这里有一些区别:
- 每个实体首先都必须有自己的主键,所以Bravo、Charlie等表应该在ad中定义自己的代理键
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');