如何在SQL表中实现此数据结构

时间:2012-06-05 20:50:25

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

我遇到的问题可归纳如下:

假设我正在实施员工数据库。对于每个人取决于他的位置,应填写不同的领域。因此,例如,如果员工是软件工程师,我有以下列:

Name
Family
Language
Technology
CanDevelopWeb 

如果员工是业务经理,我有以下栏目:

Name
Family
FieldOfExpertise
MaximumContractValue
BonusRate

如果员工是销售员,那么其他一些栏目等等。

如何在数据库架构中实现此功能?

我认为有一种方法是拥有一些相关的表格:

CoreTable:

Name
Family
Type

如果type为1,那么该员工是软件开发人员,因此剩下的信息应该在表SoftwareDeveloper中:

Language
Technology
CanDevelopWeb 

对于业务经理,我有另一个包含列的表:

FieldOfExpertise
MaximumContractValue
BonusRate

这个结构的问题是我不知道如何在表之间建立关系,因为一个表与一列上的几个表有关系。

如何加强关系完整性?

7 个答案:

答案 0 :(得分:3)

这里有一些思想流派。

(1)在一个表中存储可以为空的列,并且只填充相关的列(检查约束可以在这里强制完整性)。有些人不喜欢这样,因为他们害怕NULL。

(2)你的多表设计,每个类型都有自己的表。更难以强制执行DRI,但可能对应用程序或触发逻辑微不足道。

其中任何一个问题的唯一问题是,只要添加新属性(如CanReadUpsideDown),就必须进行架构更改以适应这种情况 - 在(1)中您需要添加新属性列和新约束,在(2)中,如果代表员工的新“类型”,则需要添加新表。

(3)EAV,您有一个存储属性名称和值对的表。您在这里对数据完整性的控制较少,但您当然可以将属性名称约束为某些字符串。我在这里写到了这个:

答案 1 :(得分:2)

您正在描述用于实现类别(又称继承,泛化,子类)层次结构的3 possible strategies的一个(“每个表的类”)。

PK从父表到子表的正确“传播”自然地通过它们之间的直接外键强制执行,但确保子行的存在和排他性是另一回事。它可以完成(如上面的链接所示),但增加的复杂性可能不值得,我通常建议在应用程序级别处理它。

答案 2 :(得分:1)

  1. 我会在EmployeeId
  2. 中添加一个名为EmployeeTable的字段
  3. 我摆脱了Type
  4. 例如,对于BusinessManager表和SoftwareDeveloper,我将添加EmployeeId
  5. 然后,您可以从BusinessManagerSoftwareDeveloper表格到Employee
  6. 继续创建外键

答案 3 :(得分:1)

使用核心表进一步扩展您的单向方法是基于标识列创建代理键。这将为每个员工创建一个唯一的员工ID(这将有助于您区分具有相同名称的员工)。

外键保留了您的参照完整性。您不一定需要像其他人那样提及EmployeeTypeId,因为您可以在SoftwareDeveloper或BusinessManagers表中对其进行过滤。相反,该列将充当缓存的数据点,以便于查询。

您必须填写以下示例代码中的类型并重命名外键。

create table EmployeeType(
    EmployeeTypeId
,   EmployeeTypeName
,   constraint PK_EmployeeType primary key (EmployeeTypeId)
)

create table Employees(
    EmployeeId int identity(1,1)
,   Name
,   Family
,   EmployeeTypeId
,   constraint PK_Employees primary key (EmployeeId)
,   constraint FK_blahblah foreign key (EmployeeTypeId) references EmployeeType(EmployeeTypeId)
)

create table SoftwareDeveloper(
    EmployeeId
,   Language
,   Technology
,   CanDevelopWeb
,   constraint FK_blahblah foreign key (EmployeeId) references Employees(EmployeeId)
)

create table BusinessManagers(
    EmployeeId
,   FieldOfExpertise
,   MaximumContractValue
,   BonusRate
,   constraint FK_blahblah foreign key (EmployeeId) references Employees(EmployeeId)
)

答案 4 :(得分:1)

在这种情况下,现有的SQL引擎都没有可以让您轻松生活的解决方案。

您的问题在"数据库管理中的实际问题",在实体子类型"的章节中进行了相当大的讨论。值得称道的阅读,不仅适用于这一章。

从逻辑设计的角度来看,正确的解决方案与您的类似,但对于"类型"核心表中的列。你并不需要这样,因为你可以得到''类型'员工出现在哪个非核心表中。

您需要关注的是业务规则,即数据约束,它们将确保数据的整体完整性(即一致性)(当然,这些实际上是否适用于您的业务用户,而不是我,应该是告诉你):

每个指定的员工必须只有一份工作,因此某些工作细节。 iow:(1)没有任何工作细节的命名员工和(2)没有> 1工作细节的命名员工。

(3)所有工作细节必须是指定员工。

其中,如果您使用的是SQL引擎,那么(3)是唯一可以声明性地实现的方法。它只是从非核心表到核心表的常规FK。

(1)和(2)可以在标准SQL中以声明方式定义,使用CREATE ASSERTION或CHECK CONSTRAINT,涉及对定义CHECK CONSTRAINT的表之外的其他表的引用,但任何这些构造都不受任何构造的支持。我知道的SQL引擎。

为什么[包括]'类型'列是一个相当糟糕的选择:它改变了约束(3)必须如何形成。例如,您不能再说'#34;所有业务经理必须被命名为员工",而是您必须说"所有业务经理都是名为员工,其类型为< type here> ;&#34 ;. Iow,"常规FK"现在,您的核心表已成为核心表上 VIEW 的引用,您可能希望将其声明为,

CREATE TABLE BUSMANS ... REFERENCES(SELECT ... from CORE TYERE TYPE =' BM');

创建视图BM AS(选择...来自核心类型=' BM'); CREATE TABLE BUSMANS ...参考文献BM;

SQL再一次不允许你这样做。

答案 5 :(得分:0)

您可以使用同一个表中的所有字段,但是您需要一个名为Employee_Type的额外表格(例如),在这里您必须放置Developer, Business Manager, ...当然还有一个唯一的ID。因此,employee_type_id中的关系将为Employee table

使用PHP或ASP,您可以根据下拉菜单中的employee_type_id(或文本)控制要显示的字段。

答案 6 :(得分:0)

你走在正确的轨道上。您可以设置从常规人员表到每个专用表的PK / FK关系。您应该为所有表添加personID以用于关系,因为您不希望在名称上设置关系,因为它不能是PK,因为它不是唯一的。名称也发生变化,它们是FK关系的一个非常差的选择,因为名称更改可能导致许多记录需要更改。使用单独的表而不是一个表是很重要的,因为其中一些表是一对多的关系。对于instnce的开发人员可能有许多不同的技术,并且应该永远不要将这些东西存储在逗号分隔的列表中。

如果主记录具有特定的personType,您还可以设置触发器以强制记录只能添加到专业表中。但是,要小心这样做,因为你会随着时间的推移改变角色。你是否想要失去这个人在被提升为经理时成为开发人员时所知道的历史。然后,如果他决定退回到发展(频繁发生),你将不得不重新创建他的旧记录。