数据库设计(1/9):数据元(Data Elements)

对于设计和创建数据库完全是个新手?没关系,Joe Celko,世界上读者数量最多的SQL作者之一,会告诉你这些基础。和往常一样,即使是最专业的数据库老手,也会给他们带来惊喜。Joe是DMBS杂志是多年来最受读者喜爱的作者。他在美国、英国,北欧,南美及非洲传授SQL知识。他在ANSI / ISO SQL标准委员会工作了10年,为SQL-89和SQL-92标准做出了杰出贡献。


在你开始考虑你的数据库架构或表前,你需要细想下你的数据:数据是什么类型,你使用值的范围。它应该是唯一的,精确的且不含糊的。然后你的命名应该通俗易懂的。Joe Celko这样解释道。

不要太惊讶,在数据库设计里第一步是数据。但事实上,太多的程序员不会花时间在它们的数据设计上,而是首先设计架构。这样行不通。SQL处理的是结构化数据,而不是想文本或图片的非结构化数据。在关系型数据库管理系统(RDBMS)里一个基本概念是Codd博士所谓的信息原则(Information Principle)。这个规则写道:在关系型数据库管理系统里,所有的数据被建模为表里行里列里的标量。

这就是说表里的所有行有同样的结构。也就是说正确的表设计不会出现有一行是汽车的模型,另一行是鱿鱼的模型,还有一行表示Lady Gaga。

同样,这就是说行里的每列是同样数据元的值。在表里,一个列不会从鞋子大小变成其它温度的值。也就是说范围不会改变——如果你以摄氏度测量温度,那么这列的所有值都使用摄氏度的范围。

选择数据的范围和类型很重要。它让在一些范围内做数学和比较有意义,而不是与其它。这也解释了为什么SQL 是强类型语言(strongly typed language)。一些语言是弱类型的——那就是,变量在程序执行期间可以修改数据类型——一些则是强类型的;那些就是变量保持同样的数据类型,只有你在强制转化的时候才会是新的数据类型。并不是所有的强制转化都合法。弱类型转化问题的经典例子是PL/I里,如果你分配单个数组元为负数的平方根,它会把整个数组从FLOAT转为COMPLEX类型。这个发生的时候没有任何警告信息。关于弱数据类型有个老笑话:

教师:“比利,6乘以9多少?”

比利:“额~~,红色?”

教师:“不是!萨利,6乘以9多少?”

萨利:“星期四?”

教师:“不是!汤米,6乘以9多少?”

汤米:“54”

教师:“回答正确!现在告诉大家你怎么得到答案的。”

汤米:“我用红色除以星期四!”

人们在写弱类型语言时,经常会在数据元名称加上前缀或词尾,告诉大家原始数据类型,防止在程序中大家修改类型。这违反了ISO-11179元数据规则。这个标准总结了命名数据元是它本身应该是什么,而不是它在存储中的位置,或者在表里如何使用。

对于数据元,ISO_11179格式是“[<角色>_]<属性名>_<特征名>]"(“[<role>_]<attribute>_<property>”)。在整个架构里,一个数据元有一个且只有一个名称。如果在整个企业里有且只有一个名称更佳。最好的话,在宇宙里有且只有一个名称。我来告诉你另一个老笑话:

“我是小孩时,我们有三只猫。”

“它们的名字是什么?”

“猫,猫和猫。”

“听起来分不清;你怎么把它们区分开?”

“谁在乎呢?当你叫它们时,它们也不会过来!”

我们希望数据在叫的时候就知道它是什么。逻辑上称同一律(the Law of Identity),通常简单的从字面上说A就是A。更正式的话,我们称作:

  1. “是”就特指某物;实体应有名称。
  2. “不是”任何特定之物,就彻底不是任何事物;实体应是唯一且精确的。
  3. “是”任何一般之物,就彻底不是任何(其它)事物;实体应无二义性。

例如,没有一个东西可以是“id”——它太模糊,太通用(它是用来标识汽车,鱿鱼还是布兰妮·斯皮尔斯么?)。它是没有性质的属性。更好的命名会是”vehicle_id",如果那是我们有的属性性质(attribute property)。最好的数据元名称是“vin”,这个是普遍使用和定义的ISO 4030“车辆识别码(Vehicle Identification Number)”标准。VIN精确且很好理解。

同样,你也会看到没有性质的属性。我个人最爱的是“sex”,它可以是“sex_code”(按ISO 5218定义,可以参考它的标志符“SEX”,虽然这不是个好主意)。"sex_type"(动物或植物的生理选项:雄性还是雌性)或者“sex_frequency”(在我这一厢情愿的想法)。

可能最荒谬的错误是性质链。想下“type_code_id”什么意思。如果它是个标识,俺么在数据模型里它是唯一的并属于一个实体(想下"emp_id")。如果它是个代码,那么它有个外部的权威(想下“邮编”)。如果它是个类型,那对它有个测试(想下“血型”)。这就像没有一个名词来修改的一连串形容词。增加一个属性到链不会拯救含糊问题。

再次强调,基本规则是一个数据元名词告诉我们它是什么。名称不会告诉我们:

  1. 有表名的架构里它的位置
  2. 在特定表里它如何使用的(例如在名称里没有pk-,fk-或vw-等词缀的话)
  3. 它的数据如何物理存储的(例如对于整形、字符型等没有“i-”,“str-”等词缀)
  4. 没有告诉我们数据元不是什么。要确定并精确。

性质组件是从标准化列表里选取,你可以按需添加。这个列表成为你数据字典的一部分,并需要被执行。

在同个表里,当同样的数据元出现2个或更多的角色,要用到<角色>。例如,在组织报表里会有“supervisor_emp_id”和“subordinate_emp_id”,都来自Personnel表里的员工标识数据元“emp_id”。

来看下名称的长度。数据元名称太长或太短都不好。太短的名称很难理解,除非它是标准的缩写。它们也会模棱两可;我最喜欢的例子是一个系统,在数据元名称里有多个student的缩写方式,其中一个是“std”——经常会被误认为是“standard”的缩写,在有些地方甚至是“sexually transmitted disease(性病,由性交引起的病)”。

在名称里避免所有的特殊字符。坚持使用Latin-1字母,数字和下划线。它们会在其它程序语言里复用。没错,数据元名称不只为SQL。同样,避免同时使用仅微软支持的方括号“["或者仅ANSI/IOS支持的双引号标记。这个只是为在数据库里显示格式草率的编程完成,而不是前端显示。有一个可能的异常会是语言翻译问题,Latin-1字母不能正常工作。

执行大写规则来避免大小写敏感问题。我的规则是SQL 关键字是大写,标量数据元是小写,架构对象是大写。在我的《SQL 编程风格(Sql Programming Style )》书里有这方面的研究,但这里我会跳过细节。

对于数据元素名称的标准化性质后缀列表是基于Teradata的内部标准建立,在行业刊物上通用(CMP,MKP和其它出版商)。这些后缀有精确的含义。如果你需要发明你自己的,它们也要是精确的。

"_id"=标识者。在架构里它是唯一的,在架构里任何地方它指的是一个实体。唯一性和标识者不是同个东西。圆周率数字它是唯一的,但他不能标识一个实体。绝不使用“<表名>_id";这是基于位置的名字,并告诉你很可能这不是个真正的主键。简单的”id“太含糊,当你有无限个这样的名称,你就吧你的数据字典弄混。显然,自增长值也不是个标识。我一会谈下这个谬论。

"_date"或"_dt"=日期时间的维度。它是一些时间——工作,出生,终止等等。没有本身就是日期这样列名,那样会很糟糕,因为DATA在SQL里是注册的关键字。

"_nbr"或"_num"=标签数字;这是命名一些的数字字符。不要使用"_no",因为它看起来像布尔的是否值。我更喜欢"nbr"或"num",因为在多个欧洲语言里,它是常见的缩写,而且在"_num"里类似形状字母的组合会有视觉混淆。

"_name"或"_nm"=这是个字母名称本身就能看懂。它也成为名称量表。

"_code"或"_cd"=代码,被可信源,通常是企业外标准化维护的。例如,邮编是有米国邮政服务维护的。在它的上下文里,代码很好理解,因此你可能不需要翻译它。

"_size"=对于一个商品,例如衣服,鞋子, 信封或机器螺丝的行业标准或公司规模。

"_seq"=序列,序数。和标签数不是同个东西,因为它不会缺口。

"_tot"=合计,一个聚合的维度,逻辑上不同的部分。

"_tally"=值的个数,一个聚合的维度。也称为绝对标度。

"_status"=一个内部编码,反射了在知道的模式里将要修改的状态。考虑下军事地位。你会出生,然后改变状态到合法年龄。同时你不能和多个人结婚。你可以从已婚状态修改为离婚,从离婚变成已婚。如果你死了的话,就不能结婚。

"_cat"=分类,来自内部源的需要官方判定的编码。例如,五个飓风的类别。这不像个代码,需要这样的官方判定。

"_class"=不需要外部源的内部编码。一个类别就有一些共性一系列东西;对于动物分类你有规则,是哺乳还是爬行。有些情况你很难使用这些规则,例如在澳大利亚的哺乳动物,但是例外会变成它们自己的分类——单孔目。

"_type"=内外都有同样含义的编码。血型有新定义的测试过程。比起class,type通常更不正式,且会有重叠。type是三类中最弱的,它需要一个判断。在一些州,三轮摩托车是作为摩托车注册。在其它州,会作为汽车。在一些州,如果它有倒车档的话,也会作为汽车。

在实际的使用中,这3个方面会混淆。因此以行业标准来,即使它违反了上述的定义。

"_addr"或"_loc"=实体的地址或位置。地址和位置间有微妙的区别。地址可以指的是街道地址或一些外部的地理系统。位置指的是内部架构,例如仓库仓号。仓号可以保持一样,即使物理位置改变了。

"_img"=图片数据类型,例如.jpg,  .gif等等。使用特定的格式作为性质会是重要的。

如果需要的话,可以随意添加。但记得跟踪并标准化你所做的。

原文链接:http://www.sqlservercentral.com/articles/Stairway+Series/69801/

上一篇:银行卡号码校验算法(Luhn算法,又叫模10算法)


下一篇:数据库设计范式1——三范式