数据库设计(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。更正式的话,我们称作:
- “是”就特指某物;实体应有名称。
- “不是”任何特定之物,就彻底不是任何事物;实体应是唯一且精确的。
- “是”任何一般之物,就彻底不是任何(其它)事物;实体应无二义性。
例如,没有一个东西可以是“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")。如果它是个代码,那么它有个外部的权威(想下“邮编”)。如果它是个类型,那对它有个测试(想下“血型”)。这就像没有一个名词来修改的一连串形容词。增加一个属性到链不会拯救含糊问题。
再次强调,基本规则是一个数据元名词告诉我们它是什么。名称不会告诉我们:
- 有表名的架构里它的位置
- 在特定表里它如何使用的(例如在名称里没有pk-,fk-或vw-等词缀的话)
- 它的数据如何物理存储的(例如对于整形、字符型等没有“i-”,“str-”等词缀)
- 没有告诉我们数据元不是什么。要确定并精确。
性质组件是从标准化列表里选取,你可以按需添加。这个列表成为你数据字典的一部分,并需要被执行。
在同个表里,当同样的数据元出现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/
数据库设计(1/9):数据元(Data Elements)的更多相关文章
- 数据元&数据字典&元数据
1. 数据元 data element(数据元素),单个数据单元,是数据的基本单位.参阅data field(数据字段). 2. 元数据 首先,我们举个例子来看看什么叫做“元”,在后现代主义文学中有一 ...
- Mysql之数据库设计
一.三大范式 1.第一范式:消除一个字段包含多个数据库值,消除一个记录包含重复的组(单独的一列包含多个项目),即可满足1NF. 2.第二范式:消除部分依赖性即可转化为2NF.部分依赖性表示一个记录中包 ...
- 基于web公交查询系统----数据库设计
要求:公交查询系统,管理员可以新增线路,修改车辆参数,发车时间表,删除车次,站名等. 用户可以按线路查询,按站点查询相关信息,也可查询两站点之间的换乘信息等. 数据库应包含管理员表,车站表,线路表,车 ...
- 大数据量查询优化——数据库设计、SQL语句、JAVA编码
数据库设计方面: 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将 ...
- navicat data modeler的使用以及数据库设计的流程
E-R图(Entity Relationship Diagram) 又称实体-联系图 (提供了表示实体类型.属性和联系的方法,用来描述现实世界的概念模型) 构成E-R图的3个基本要素是实体型.属性和联 ...
- 数据库设计_ERMaster安装使用_PowerDesigner数据设计工具
数据库设计 1. 说在前面 项目开发的流程包括哪些环节 需求调研[需求调研报告]-- 公司决策层 (1) 根据市场公司需求分析公司是否需要开发软件来辅助日常工作 (2) 公司高层市场考察,市场分析,决 ...
- mySQL教程 第1章 数据库设计
E-R设计 很多同学在学SQL语句时,觉得非常困难,那是因为你在学一个你根本不了解的数据库,数据库中的表不是你设计的,表与表之间的关系你不明白.因此在学SQL语句之前,先介绍一下数据库设计. 下面举例 ...
- 数据库设计中的Soft Delete模式
最近几天有点忙,所以我们今天来一篇短的,简单地介绍一下数据库设计中的一种模式——Soft Delete. 可以说,该模式毁誉参半,甚至有非常多的人认为该模式是一个Anti-Pattern.因此在本篇文 ...
- 优化MySchool数据库设计之【巅峰对决】
优化MySchool数据库设计 之独孤九剑 船舶停靠在港湾是很安全的,但这不是造船的目的 By:北大青鸟五道口原玉明老师 1.学习方法: 01.找一本好书 初始阶段不适合,可以放到第二个阶段,看到知识 ...
随机推荐
- Event,delegate,handler之间的关系
在C#或者说.Net的事件处理机制中,有三个关键的概念 - 事件(Event),委托(Delegate)和处理器(Handler),另外在面向对象的背景中,还有另外两个概念 - 发送者(Sender) ...
- 禁用SQL Server Management Studio的IntelliSense
禁用SQL Server Management Studio的IntelliSense 本文版权归作者所有,未经作者同意不得转载.
- ENode框架Conference案例分析系列之 - 业务简介
前言 ENode是一个应用开发框架.通过ENode,我们可以方便的开发基于DDD+CQRS+EventSourcing+EDA架构的应用程序.之前我已经写了很多关于ENode的架构以及设计原理的文章, ...
- java中文乱码解决之道(六)-----javaWeb中的编码解码
在上篇博客中LZ介绍了前面两种场景(IO.内存)中的java编码解码操作,其实在这两种场景中我们只需要在编码解码过程中设置正确的编码解码方式一般而言是不会出现乱码的.对于我们从事java开发的人而言, ...
- [ASP.NET MVC 小牛之路]06 - 使用 Entity Framework
在家闲着也是闲着,继续写我的[ASP.NET MVC 小牛之路]系列吧.在该系列的上一篇博文中,在显示书本信息列表的时候,我们是在程序代码中手工造的数据.本文将演示如何在ASP.NET MVC中使用E ...
- 谁占了我的端口 for Windows
这篇文章发布于我的 github 博客:原文 今天在本地调试 Blog 的时候意外的出现了一些错误:127.0.0.1 4000 端口已经被其他的进程占用了.如何找到占用端口的进程呢? Configu ...
- 老司机学新平台 - Xamarin开发之我的第一个MvvmCross跨平台插件:SimpleAudioPlayer
大家好,老司机学Xamarin系列又来啦!上一篇MvvmCross插件精选文末提到,Xamarin平台下,一直没找到一个可用的跨平台AudioPlayer插件.那就自力更生,让我们就自己来写一个吧! ...
- Android开发学习之路-提升用户体验小技巧
记得之前看谷歌的一个视频提到这个用户体验的问题,今天想起来了就写了个Demo来记录下. 当一个事件发生之后,用户需要一段时间才能知道结果,那么这段时间究竟应该让用户干什么?这个问题很常见,比如我们的软 ...
- Java Thread 的使用
Java Thread 的使用 Java Thread 的 run() 与 start() 的区别 Java Thread 的 sleep() 和 wait() 的区别 一.线程的状态 在正式学习 ...
- android/java 根据当前时间判断股票交易状态(未开盘 交易中 休市中 已收盘)
/** * @param data yyyy-MM-dd HH:mm:ss 时间 * @return 未开盘 交易中 休市中 已收盘 */ public static String getSotckS ...