您的位置:首页 > 数据库

如何保证数据库结构的合理性(二、调整表结构)

2013-06-21 17:18 281 查看
(二)表的调整

表是创建SQL查询的基础。设计不好的表会导致数据完整性方面的问题,并且在多表查询时会遇到困难。因此,必须先确保所涉及的数据表的结构尽可能高效,这样才能方便地提取数据。

1)表名称的调整

表创建了就应该描述一个特定的物体,如果其描述的物体超过一个,那么就应该将其分割为几个小的表。表的名称必须清楚地标识所描述的物体。如果一个表名称是不够明确、会产生歧义或者意义不清楚,那么肯定对这个表所描述饿对象考虑得不是很周详。可以通过下面各项来检查表名称是否合理。

1.在整个组织中此名称是否惟一并且具有描述意义?

给数据库中的表一个惟一的名称,确保所描述的是不同的物体而且组织中的每一个人都能明白表所描述的是什么。定义一个惟一的说明性的名称虽然不是份内的工作,但这样做还是值得的。

2.名称是否清楚、精确、没有歧义地标识该物体?

当表名称意义含混不清有歧义时,就可以确定这个表描述的物体可能多于一个。“Dates”就是一个很好的说明例子,它的表名含糊不清。这时很难确定表所描述的内容,除非手边同时有其他相关的说明资料。这种情况下,不妨将表分成多个表并且分别给予正确的命名。

3.名称中是否有表述物理特性的词?

避免使用这样的字词如“文件”、“记录”、“表”,因为这样会引起一定的混淆,使用这一类型的词的表名称看起来很像是描述多个物体。

假定有这样的名称“Employee_Record”,表面上,这个名称没有任何问题,但是当考虑到它应该描述的是什么样的雇员记录的时候,就会认识到这个名称暗含的问题。这个名称包含了我们尽量避免的词,它可能描述了三个事物:雇员employees、部门departments和薪水册payroll。考虑到这点,可将原来的表(Employee_Record)分成三个表,没一个表描述一个事物。

4.是否使用首字母缩写或者其他缩写形式作为一个表的名称?

缩写形式很少能表述清楚事物,首字母缩写通常也很难解释。

比如公司的数据库中有表SC,不同部门可能会把这个表理解成不同的事物。人事部的人会认为它代表着Steering_Committees;信息系统处的人相信它是System_Configurations;安全处的人会觉得是Security_Codes。这个例子就很好地说明了为什么要避免使用首字母缩写和其他缩写形式作表的名称。

5.使用的名称是否暗含或者明确描述了多个事物?

这种类型的名称一般包含有“and”“or”这样的字词或者反斜线(\)、连字符(-)、与连接符(&)等字符。以这种方式为表命名时,必须弄清楚该表是否描述了多个事物,如果是,请将它拆分成为多个小的表,然后给每个表一个合适的名称。

6.最后检查每一个表的名称,确保表名称是复数形式。

使用复数形式是因为表所存储的是所代表事物的具体实例的集合。

2)确保良好的结构

表结构合理是绝对有必要的,只有这样才能有效地存储数据,并提取到准确的信息。确保表的结构合理需要花费一些时间,但这在创建复杂的多表SQL查询时却会获益不小。可以根据下面列表中的内容检查表结构是否合理。

1.确保表所描述的是一个单一的事物。

这个已经多次提到过,但再怎么强调其重要性也不过分。只要保证了每一个表描述一个单一事物,就会大大降低可能的数据完整性危险问题。

2.确保每一个表有一个主关键字。

必须给表分配一个主关键字,原因有二:一是主关键字能惟一标识表中的每一个记录,二是主关键字用来建立表之间的关联关系。如果没有给每一个表指定主关键字,最终将会遇到有关数据完整性的问题和一些类型的SQL多表查询问题。

3.确保表中没有任何多值和多型字段。

理论上,在对字段结构进行改进后,这一问题就不会存在了。虽然如此,最后再检查一遍,确保这样两种情况都不存在,仍不失为一个好主意。

4.确保表中没有计算字段。

虽然很可能相信当前的表中不存在计算列,但也可能在字段修正时忽略了那么一两个。现在是时候再查看一遍并把漏掉的计算列删除掉。

5.确保表中没有任何不必要的复制列。

设计不好的表结构的特点之一就是它包含了其他表中的复制列。可能由于这样一两个原因会让你觉得不得不添加复制列到表中,比如:提供“引用”信息,或标志一个特定类型值的多次出现。这些复制列在数据操作或信息提取时会制造很多麻烦。下面会看到如何处理这样的复制列。

3)不必要的复制列的处理

下图是一个包含参考信息的复制列的表。



(PS:特别说明一下,这里的Staff表中,Staff表示的是全体职员,我刚开始以为书里面印刷错误少印了复数形式。)

在这种情况下,Classes表中有StaffLastName和StaffFirstName字段,这样查看表的人就能看到某个指定班级指导员的姓名。然而,由于在Classes和Staff表之间已经存在1:M的关系,这两列就属于非必要复制列。(一个教员可以指导很多班级,而一个班级只能由一个指定的教员指导。)StaffID建立了这两个表之间的联系,此联系让人在一个SQL查询中可以同时从两个表中查看数据。考虑到这点,就可以大胆地把Classes表中的StaffLastName和StaffFirstName字段删除,而不会有任何副作用。下面是修改后的表结构。



如果保留这些不必要的字段,随后所出现的最主要的问题就是数据的不一致。必须要保证Classes表中的StaffLastName和StaffFirstName字段的值和Staff表中相应的部分总是匹配对应的。

比如一位女教员结婚了并打算从此将夫姓作为她的法定姓名。这时不仅要对Staff表中她的记录作合适的修改,还要确保Classes表中所有出现她姓名的地方都要作相应的修改。而以后有可能还有这样的工作要做,这样就做了很多不必要的辛苦工作。除此之外,使用关系数据库最主要的一个前提就是在整个数据库中一块数据只应该输入一次。(例外情况即这个字段是用来建立两个表之间的联系。)最好的处理方式就是把数据库中所有的复制字段删除。

下面这个表是复制字段的另一个很清楚的例子。这个例子中,复制列被错误地用于指示一个特定值的多种情况。在这种情况下,从表面上看,三个Committee字段用来记录雇员参加的委员会的名称。



这样的复制列会导致什么问题呢?

第一个问题就是考虑到表中实际应有的Committee字段数目的时候。如果有一些雇员所属的委员会有四个呢?就这个问题,如何能判断应该有多少Committee字段才能满足需求?如果现在已经出现了几个雇员他们所属的委员会多于三个,那么就需要给这个表添加另外的Committee字段。

第二个问题会出现在从表中提取信息的时候。如何取出目前属于Y2K Conformance委员会的信息?当然这也不是不可能,但是得到这些信息会很困难。为了得到正确的答案,必须执行三个不同的查询,这是因为没有办法确定Y2K Conformance到底是存在三个Committee字段中的哪一个中。这样就要花费更多的时间和精力。

第三个问题会出现在存储数据的时候。我们不能按Committee对数据做任何方式的排序,也没有办法把委员会的名称按字母顺序进行正确的排列。这好象是一个小问题,但当要对所有数据按某一方式进行排序查看时就是一个令人生畏的问题了。

如果仔细研究一下Employees就不难发现雇员和委员会之间存在一个多对多的关系。一个雇员可以属于多个委员会,而某一个委员会也可以有多个雇员参加。因此,可以使用处理任何多对多关系的方式来解决问题——创建一个关联表。在此,使用Employees表的主关键字(EmployeesID)拷贝和一个单独的Committee字段建立一个关联表,并给这个表一个合适的名字,如Committee_Members,指定字段EmployeesID和CommitteeID作为组合关键字,把Committee字段从Employees表表删除,这就完成了对复制列的处理。下图就是修改后的Employees表和新的Committee_Members表。



在处理完远Employees表中的复制列后,问题还没有完。雇员和委员会之间存在一个多对多的关系,还缺少一个委员会的表。另外一个委员会可能其他的一些特征是需要记录的,比如,委员们聚会用的房子的名称,聚会的日期时间等。因此,应该创建一个真正的Committee表,包含这样一些字段,如CommitteeID、CommitteeName、MeetingRoom和MeetingDay。创建好这样一个表后,把Committee_Members表中的字段Committee用新的Committees表中的CommitteeID字段代替。下图就是最后的结构。



以这样方式组织的表,有很多实际的优点,现在我们就可以把一个雇员和许多委员会相关联,而一个委员会也可以由很多成员组成。也可以使用一个SQL查询语句同时从三个表中取得信息。

到现在为止,对表结构的调整过程就快结束了。还有最后一件事情就是要确保表中的每一个记录都可以被惟一标识,并且表本身在整个数据库中也能被惟一标识。

4)关键字标识

在一个表中主关键字是最主要的关键字之一,这是因为它能惟一地标识表中的每一个记录,同时也可以用来在数据库中标识表,它还用于建立两个表之间的关联关系。不能低估主关键字的重要性——数据库中的每一个表都必须有一个主关键字!

主关键字由一个或者一组字段来定义,能惟一标识表中的记录。由单一字段组成的主关键字成为单主关键字,由两个或者两个以上的字段组成的主关键字称为复合主关键字。由于单主关键字更有效而且在建立表关系的时候更容易使用,所以在允许的情况下都定义一个单主关键字。而复合关键字只有在适当的时候才使用(比如,创建一个关联表的时候)。

只有一个字段满足下面列表中的所有条件,就可以用它作为一个主关键字。如果字段不能符合所有标准,那么就用其他字段或者定义一个新的字段作为主关键字。现在用下面列表中的内容来检验数据库中的每一个主关键字是否合理。

1.这个字段是否能惟一标识表中的每一条记录?

表中的每一条记录描述的是表对象的一个具体的实例。一个好的主关键字应该确保用户以准确的方式和另一个表中的记录以示区别,或者关联这个表中的记录到数据库中的另一个表。它可以避免表中完全相同的记录出现。

2.这个字段的值是否惟一?

只有主关键字的值是惟一的,才能确保不会出现完全相同的记录。

3.这个字段是不是会有空值?

这是洋很重要的问题,因为主关键字不能包含空值。如果这个字段还是可能(即使这个机会概率很小)会存在空值,应该立即把主关键字换成其他字段。

4.这个字段的值是否会是可选的?

如果答案是“yes”,那么这个字段不能用来作为关键字。如果这个字段的值是可选择的,这意味着在某一时刻它可能是空值,而由前面一条我们也知道,主关键字是不允许包含空值的。

5.是不是多型字段?

尽管到现在可能已经去掉了所有的多型字段,但这个问题还是应该时刻警惕。如果这是一个前面处理过程中被忽略的多型字段,那么就应对这个字段进行处理,并尽量用其它的字段来定义主关键字。

6.这个字段是否能被修改?

主关键字的值应该是静态的。也就是说,主关键字的值不能修改,除非真的有不得不这么做的理由。如果主关键字的值被随意修改,那这个字段就很难再满足该列表中的其它条款。



像上图Pilots表中的PilotID就是一个合适的主关键字,因为它符合上面列表中的所有要点。但如果假设没有任何的字段作为主关键字,那又会怎么样?比如下图中的Employees表,是否有一个可以作为主关键字的字段?



很清楚的是表中没有一个字段(或一组字段)可以作为主关键字,除了EmpPhone字段外,其他的字段都有相同的值,EmpZip、EmpAreaCode和EmpPhone都还有空值。由于表中的字段都是可以随意更改的,显而易见表中也没有能作为主关键字的字段。这时就需要人为地创建一个主关键字。

定义并添加一个强制字段到表中,就是为了用作表的主关键字。添加这样的一个强制性字段的好处就在于它能很好地满足列表中的所有条件。一旦把这样的字段添加到表中并定义为主关键字,表就有主关键字了。这就是处理的方法。下图就是添加了这样一个新的主关键字字段EmployeeID后的表。



现在已经完成了对表结构的加强和修正。下篇来看看如何保证表间关系的合理性和正确性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: