第1 部分— 设计数据库之前
这一部分罗列了12 个基本技巧,包括命名规范和明确业务需求等。
第2 部分— 设计数据库表
总共24 个指南性技巧,涵盖表内字段设计以及应该避免的常见问题等。
第3 部分— 选择键
怎么选择键呢?这里有10 个技巧专门涉及系统生成的主键的正确用法,还有何时以及如何索引字段
以获得最佳性能等。
第4 部分— 保证数据完整性
讨论如何保持数据库的清晰和健壮,如何把有害数据降低到最小程度。
第5 部分— 各种小技巧
不包括在以上4 个部分中的其他技巧,五花八门,有了它们希望你的数据库开发工作会更轻松一些。
--------------------------------------------------------------------------------
第1 部分— 设计数据库之前
1. 考察现有环境
在设计一个新数据库时,你不但应该仔细研究业务需求而且还要考察现有的系统。大多数数据库项目都不是从头开始建立的;通常,机构内总会存在用来满足特定需求的现有系统(可能没有实现自动计算)。显然,现有系统并不完美,否则你就不必再建立新系统了。但是对旧系统的研究可以让你发现一些可能会忽略的细微问题。一般来说,考察现有系统对你绝对有好处。
我曾经接手过一个为地区运输公司开发的数据库项目,活不难,用的是Access 数据库。我设置了一些项目设计参数,而且同客户一道对这些参数进行了评估,事先还查看了开发环境下所采取的工作模式,等到最后部署应用的时候,只见终端上出了几个提示符然后立马在我面前翘辫子了!抓耳挠腮的折腾了好几个小时,我才意识到,原来这家公司的网络上跑着两个数据库应用,而对网络的访问需要明确和严格的用户帐号及其访问权限。明白了这一点,问题迎刃而解:只需采用客户的系统即可。这个项目给我的教训就是:记住,假如你在诸如Access 或者Interbase 这类公共环境下开发应用程序,一定要从表面下手深入系统内部搞清楚你面临的环境到底是怎么回事。
2. 定义标准的对象命名规范
一定要定义数据库对象的命名规范。对数据库表来说,从项目一开始就要确定表名是采用复数还是单数形式。此外还要给表的别名定义简单规则(比方说,如果表名是一个单词,别名就取单词的前4 个字母;如果表名是两个单词,就各取两个单词的前两个字母组成4 个字母长的别名;如果表的名字由3 个单词组成,你不妨从头两个单词中各取一个然后从最后一个单词中再取出两个字母,结果还是组成4 字母长的别名,其余依次类推)对工作用表来说,表名可以加上前缀WORK_ 后面附上采用该表的应用程序的名字。表内的列要针对键采用一整套设计规则。比如,如果键是数字类型,你可以用_NO 作为后缀;如果是字符类型则可以采用_CODE 后缀。对列名应该采用标准的前缀和后缀。再如,假如你的表里有好多“money”字段,你不妨给每个列增加一个_AMT 后缀。还有,日期列最好以DATE_作为名字打头。
检查表名、报表名和查询名之间的命名规范。你可能会很快就被这些不同的数据库要素的名称搞糊涂了。假如你坚持统一地命名这些数据库的不同组成部分,至少你应该在这些对象名字的开头用table、query 或者report 等前缀加以区别。
如果采用了Microsoft Access,你可以用qry、rpt、tbl 和mod 等符号来标识对象(比如
tbl_Employees)。我在和SQL Server(或者Oracle)打交道的时候还用过tbl 来索引表,但我用sp_company (现在用sp_feft_)标识存储过程,因为在有的时候如果我发现了更好的处理办法往往会保存好几个拷贝。我在实现SQL Server 2000 时用udf_ (或者类似的标记)标识我编写的函数。
3. 预先计划
上个世纪80 年代初,我还在使用资产帐目系统和System 38 平台,那时我负责设计所有的日期字段,这样在不费什么力气的情况下将来就可以轻松处理2000 年问题了。许多人给我说就别去解决这一问题了,因为要处理起来太麻烦了(这在世人皆知的Y2K 问题之前很久了)。我回击说只要预先计划今后就不会遇到大麻烦。结果我只用了两周的时间就把程序全部改完了。因为预先计划的好,后来Y2K 问题对该系统的危害降到了最低程度(最近听说该程序甚至到了1995 年都还运行在AS/400 系统上,唯一出现的小问题是从代码中删除注释费了点工夫)。
4. 获取数据模式资源手册
正在寻求示例模式的人可以阅读《数据模式资源手册》一书,该书由Len Silverston、W. H.Inmon 和Kent Graziano 编写,是一本值得拥有的最佳数据建模图书。该书包括的章节涵盖多种数据领域,比如人员、机构和工作效能等。
5. 畅想未来,但不可忘了过去的教训
我发现询问用户如何看待未来需求变化非常有用。这样做可以达到两个目的:首先,你可以清楚地了解应用设计在哪个地方应该更具灵活性以及如何避免性能瓶颈;其次,你知道发生事先没有确定的需求变更时用户将和你一样感到吃惊。
一定要记住过去的经验教训!我们开发人员还应该通过分享自己的体会和经验互相帮助。即使用户认为他们再也不需要什么支持了,我们也应该对他们进行这方面的教育,我们都曾经面临过这样的时刻“当初要是这么做了该多好⋯⋯”。
6. 在物理实践之前进行逻辑设计
在深入物理设计之前要先进行逻辑设计。随着大量的CASE 工具不断涌现出来,你的设计也可以达到相当高的逻辑水准,你通常可以从整体上更好地了解数据库设计所需要的方方面面。
7. 了解你的业务
在你百分百地确定系统从客户角度满足其需求之前不要在你的ER(实体关系)模式中加入哪怕一个数据表(怎么,你还没有模式?那请你参看技巧9)。了解你的企业业务可以在以后的开发阶段节约大量的时间。一旦你明确了业务需求,你就可以自己做出许多决策了。
一旦你认为你已经明确了业务内容,你最好同客户进行一次系统的交流。采用客户的术语并且向他们解释你所想到的和你所听到的。同时还应该用可能、将会和必须等词汇表达出系统的关系基数。这样你就可以让你的客户纠正你自己的理解然后做好下一步的ER 设计。
8. 创建数据字典和ER 图表
一定要花点时间创建ER 图表和数据字典。其中至少应该包含每个字段的数据类型和在每个表内的主外键。创建ER 图表和数据字典确实有点费时但对其他开发人员要了解整个设计却是完全必要的。越早创建越能有助于避免今后面临的可能混乱,从而可以让任何了解数据库的人都明确如何从数据库中获得数据。
有一份诸如ER 图表等最新文档其重要性如何强调都不过分,这对表明表之间关系很有用,而数据字典则说明了每个字段的用途以及任何可能存在的别名。对SQL 表达式的文档化来说这是完全必要的。
9. 创建模式
一张图表胜过千言万语:开发人员不仅要阅读和实现它,而且还要用它来帮助自己和用户对话。模式有助于提高协作效能,这样在先期的数据库设计中几乎不可能出现大的问题。模式不必弄的很复杂;甚至可以简单到手写在一张纸上就可以了。只是要保证其上的逻辑关系今后能产生效益。
10. 从输入输出下手
在定义数据库表和字段需求(输入)时,首先应检查现有的或者已经设计出的报表、查询和视图(输出)以决定为了支持这些输出哪些是必要的表和字段。举个简单的例子:假如客户需要一个报表按照邮政编码排序、分段和求和,你要保证其中包括了单独的邮政编码字段而不要把邮政编码糅进地址字段里。
11. 报表技巧
要了解用户通常是如何报告数据的:批处理还是在线提交报表?时间间隔是每天、每周、每月、每个季度还是每年?如果需要的话还可以考虑创建总结表。系统生成的主键在报表中很难管理。用户在具有系统生成主键的表内用副键进行检索往往会返回许多重复数据。这样的检索性能比较低而且容易引起混乱。
12. 理解客户需求
看起来这应该是显而易见的事,但需求就是来自客户(这里要从内部和外部客户的角度考虑)。不要依赖用户写下来的需求,真正的需求在客户的脑袋里。你要让客户解释其需求,而且随着开发的继续,还要经常询问客户保证其需求仍然在开发的目的之中。一个不变的真理是:“只有我看见了我才知道我想要的是什么”必然会导致大量的返工,因为数据库没有达到客户从来没有写下来的需求标准。而更糟的是你对他们需求的解释只属于你自己,而且可能是完全错误的。
--------------------------------------------------------------------------------
第2 部分— 设计表和字段
1. 检查各种变化
我在设计数据库的时候会考虑到哪些数据字段将来可能会发生变更。比方说,姓氏就是如此(注
意是西方人的姓氏,比如女性结婚后从夫姓等)。所以,在建立系统存储客户信息时,我倾向于
在单独的一个数据表里存储姓氏字段,而且还附加起始日和终止日等字段,这样就可以跟踪这一
数据条目的变化。
2. 采用有意义的字段名
有一回我参加开发过一个项目,其中有从其他程序员那里继承的程序,那个程序员喜欢用屏幕上
显示数据指示用语命名字段,这也不赖,但不幸的是,她还喜欢用一些奇怪的命名法,其命名采
用了匈牙利命名和控制序号的组合形式,比如cbo1、txt2、txt2_b 等等。
除非你在使用只面向你的缩写字段名的系统,否则请尽可能地把字段描述的清楚些。当然,也别
做过头了,比如Customer_Shipping_Address_Street_Line_1 I 虽然很富有说明性,但没人愿意
键入这么长的名字,具体尺度就在你的把握中。
3. 采用前缀命名
如果多个表里有好多同一类型的字段(比如FirstName),你不妨用特定表的前缀(比如
CusLastName)来帮助你标识字段。
时效性数据应包括“最近更新日期/时间”字段。时间标记对查找数据问题的原因、按日期重新处
理/重载数据和清除旧数据特别有用。
5. 标准化和数据驱动
数据的标准化不仅方便了自己而且也方便了其他人。比方说,假如你的用户界面要访问外部数据
源(文件、XML 文档、其他数据库等),你不妨把相应的连接和路径信息存储在用户界面支持表
里。还有,如果用户界面执行工作流之类的任务(发送邮件、打印信笺、修改记录状态等),那
么产生工作流的数据也可以存放在数据库里。预先安排总需要付出努力,但如果这些过程采用数
据驱动而非硬编码的方式,那么策略变更和维护都会方便得多。事实上,如果过程是数据驱动
的,你就可以把相当大的责任推给用户,由用户来维护自己的工作流过程。
6. 标准化不能过头
对那些不熟悉标准化一词(normalization )的人而言,标准化可以保证表内的字段都是最基础的
要素,而这一措施有助于消除数据库中的数据冗余。标准化有好几种形式,但Third Normal
Form(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好平衡。简单来说,3NF 规
定:
· 表内的每一个值都只能被表达一次。
· 表内的每一行都应该被唯一的标识(有唯一键)。
· 表内不应该存储依赖于其他键的非键信息。
遵守3NF 标准的数据库具有以下特点:有一组表专门存放通过键连接起来的关联数据。比方说,
某个存放客户及其有关定单的3NF 数据库就可能有两个表:Customer 和Order。Order 表不包
含定单关联客户的任何信息,但表内会存放一个键值,该键指向Customer 表里包含该客户信息
的那一行。
更高层次的标准化也有,但更标准是否就一定更好呢?答案是不一定。事实上,对某些项目来
说,甚至就连3NF 都可能给数据库引入太高的复杂性。
为了效率的缘故,对表不进行标准化有时也是必要的,这样的例子很多。曾经有个开发财务分析
软件的活就是用非标准化表把查询时间从平均40 秒降低到了两秒左右。虽然我不得不这么做,
但我绝不把数据表的非标准化当作当然的设计理念。而具体的操作不过是一种派生。所以如果表
出了问题重新产生非标准化的表是完全可能的。
7. Microsoft Access 报表技巧
如果你正在使用Microsoft Access,你可以用对用户友好的字段名来代替编号的名称:比如用
Customer Name 代替txtCNaM。这样,当你用向导程序创建表单和报表时,其名字会让那些不
是程序员的人更容易阅读。
8. 不活跃或者不采用的指示符
增加一个字段表示所在记录是否在业务中不再活跃挺有用的。不管是客户、员工还是其他什么
人,这样做都能有助于再运行查询的时候过滤活跃或者不活跃状态。同时还消除了新用户在采用
数据时所面临的一些问题,比如,某些记录可能不再为他们所用,再删除的时候可以起到一定的
防范作用。
9. 使用角色实体定义属于某类别的列
在需要对属于特定类别或者具有特定角色的事物做定义时,可以用角色实体来创建特定的时间关
联关系,从而可以实现自我文档化。
这里的含义不是让PERSON 实体带有Title 字段,而是说,为什么不用PERSON 实体和
PERSON_TYPE 实体来描述人员呢?然后,比方说,当John Smith, Engineer 提升为John
Smith, Director 乃至最后爬到John Smith, CIO 的高位,而所有你要做的不过是改变两个表
PERSON 和PERSON_TYPE 之间关系的键值,同时增加一个日期/时间字段来知道变化是何时
发生的。这样,你的PERSON_TYPE 表就包含了所有PERSON 的可能类型,比如Associate、
Engineer、Director、CIO 或者CEO 等。
还有个替代办法就是改变PERSON 记录来反映新头衔的变化,不过这样一来在时间上无法跟踪
个人所处位置的具体时间。
10. 采用常用实体命名机构数据
组织数据的最简单办法就是采用常用名字,比如:PERSON、ORGANIZATION、ADDRESS 和
PHONE 等等。当你把这些常用的一般名字组合起来或者创建特定的相应副实体时,你就得到了
自己用的特殊版本。开始的时候采用一般术语的主要原因在于所有的具体用户都能对抽象事物具
体化。
有了这些抽象表示,你就可以在第2 级标识中采用自己的特殊名称,比如,PERSON 可能是
Employee、Spouse、Patient、Client、Customer、Vendor 或者Teacher 等。同样的,
ORGANIZATION 也可能是MyCompany、MyDepartment、Competitor、Hospital、
Warehouse、Government 等。最后ADDRESS 可以具体为Site、Location、Home、Work、
Client、Vendor、Corporate 和FieldOffice 等。
采用一般抽象术语来标识“事物”的类别可以让你在关联数据以满足业务要求方面获得巨大的灵
活性,同时这样做还可以显著降低数据存储所需的冗余量。
11. 用户来自世界各地
在设计用到网络或者具有其他国际特性的数据库时,一定要记住大多数国家都有不同的字段格
式,比如邮政编码等,有些国家,比如新西兰就没有邮政编码一说。
12. 数据重复需要采用分立的数据表
如果你发现自己在重复输入数据,请创建新表和新的关系。
13. 每个表中都应该添加的3 个有用的字段
· dRecordCreationDate,在VB 下默认是Now(),而在SQL Server 下默认为GETDATE()
· sRecordCreator,在SQL Server 下默认为NOT NULL DEFAULT USER
· nRecordVersion,记录的版本标记;有助于准确说明记录中出现null 数据或者丢失数据的原
因
14. 对地址和电话采用多个字段
描述街道地址就短短一行记录是不够的。Address_Line1、Address_Line2 和Address_Line3 可
以提供更大的灵活性。还有,电话号码和邮件地址最好拥有自己的数据表,其间具有自身的类型
和标记类别。
过分标准化可要小心,这样做可能会导致性能上出现问题。虽然地址和电话表分离通常可以达到
最佳状态,但是如果需要经常访问这类信息,或许在其父表中存放“首选”信息(比如
Customer 等)更为妥当些。非标准化和加速访问之间的妥协是有一定意义的。
15. 使用多个名称字段
我觉得很吃惊,许多人在数据库里就给name 留一个字段。我觉得只有刚入门的开发人员才会这
么做,但实际上网上这种做法非常普遍。我建议应该把姓氏和名字当作两个字段来处理,然后在
查询的时候再把他们组合起来。
要把这种情况变得对用户更为友好有好
些方法。我最常用的是在同一表中创建一个计算列,通过它可以自动地连接标准化后的字段,这
样数据变动的时候它也跟着变。不过,这样做在采用建模软件时得很机灵才行。总之,采用连接
字段的方式可以有效的隔离用户应用和开发人员界面。
16. 提防大小写混用的对象名和特殊字符
过去最令我恼火的事情之一就是数据库里有大小写混用的对象名,比如CustomerData。这一问
题从Access 到Oracle 数据库都存在。我不喜欢采用这种大小写混用的对象命名方法,结果还不
得不手工修改名字。想想看,这种数据库/应用程序能混到采用更强大数据库的那一天吗?采用全
部大写而且包含下划符的名字具有更好的可读性(CUSTOMER_DATA),绝对不要在对象名的
字符之间留空格。
17. 小心保留词
要保证你的字段名没有和保留词、数据库系统或者常用访问方法冲突,比如,最近我编写的一个
ODBC 连接程序里有个表,其中就用了DESC 作为说明字段名。后果可想而知!DESC 是
DESCENDING 缩写后的保留词。表里的一个SELECT *语句倒是能用,但我得到的却是一大堆
毫无用处的信息。
18. 保持字段名和类型的一致性
在命名字段并为其指定数据类型的时候一定要保证一致性。假如字段在某个表中叫做
“agreement_number”,你就别在另一个表里把名字改成“ref1”。假如数据类型在一个表里
是整数,那在另一个表里可就别变成字符型了。记住,你干完自己的活了,其他人还要用你的数
据库呢。
19. 仔细选择数字类型
在SQL 中使用smallint 和tinyint 类型要特别小心,比如,假如你想看看月销售总额,你的总额字
段类型是smallint,那么,如果总额超过了$32,767 你就不能进行计算操作了。
20. 删除标记
在表中包含一个“删除标记”字段,这样就可以把行标记为删除。在关系数据库里不要单独删除
某一行;最好采用清除数据程序而且要仔细维护索引整体性。
21. 避免使用触发器
触发器的功能通常可以用其他方式实现。在调试程序时触发器可能成为干扰。假如你确实需要采
用触发器,你最好集中对它文档化。
22. 包含版本机制
建议你在数据库中引入版本控制机制来确定使用中的数据库的版本。无论如何你都要实现这一要
求。时间一长,用户的需求总是会改变的。最终可能会要求修改数据库结构。虽然你可以通过检
查新字段或者索引来确定数据库结构的版本,但我发现把版本信息直接存放到数据库中不更为方
便吗?。
23. 给文本字段留足余量
ID 类型的文本字段,比如客户ID 或定单号等等都应该设置得比一般想象更大,因为时间不长你
多半就会因为要添加额外的字符而难堪不已。比方说,假设你的客户ID 为10 位数长。那你应该
把数据库表字段的长度设为12 或者13 个字符长。这算浪费空间吗?是有一点,但也没你想象的
那么多:一个字段加长3 个字符在有1 百万条记录,再加上一点索引的情况下才不过让整个数据
库多占据3MB 的空间。但这额外占据的空间却无需将来重构整个数据库就可以实现数据库规模
的增长了。
24. 列命名技巧
我们发现,假如你给每个表的列名都采用统一的前缀,那么在编写SQL 表达式的时候会得到大
大的简化。这样做也确实有缺点,比如破坏了自动表连接工具的作用,后者把公共列名同某些数
据库联系起来,不过就连这些工具有时不也连接错误嘛。举个简单的例子,假设有两个表:
Customer 和Order。Customer 表的前缀是cu_,所以该表内的子段名如下:cu_name_id、
cu_surname、cu_initials 和cu_address 等。Order 表的前缀是or_,所以子段名是:
or_order_id、or_cust_name_id、or_quantity 和or_description 等。
这样从数据库中选出全部数据的SQL 语句可以写成如下所示:
Select * from Customer, Order
Where cu_surname = "MYNAME"
and cu_name_id = or_cust_name_id
and or_quantity = 1;
在没有这些前缀的情况下则写成这个样子:
Select * from Customer, Order
Where Customer.surname = "MYNAME"
and Customer.name_id = Order.cust_name_id
and Order.quantity = 1
第1 个SQL 语句没少键入多少字符。但如果查询涉及到5 个表乃至更多的列你就知道这个技巧
多有用了。
--------------------------------------------------------------------------------
第3 部分— 选择键和索引
1. 数据采掘要预先计划
我所在的市场部门一度要处理8 万多份联系方式,同时填写每个客户的必要数据(这绝对不是小
活)。我从中还要确定出一组客户作为市场目标。当我从最开始设计表和字段的时候,我试图不
在主索引里增加太多的字段以便加快数据库的运行速度。然后我意识到特定的组查询和信息采掘
既不准确速度也不快。结果只好在主索引中重建而且合并了数据字段。我发现有一个指示计划相
当关键——当我想创建系统类型查找时为什么要采用号码作为主索引字段呢?我可以用传真号码
进行检索,但是它几乎就象系统类型一样对我来说并不重要。采用后者作为主字段,数据库更新
后重新索引和检索就快多了。
可操作数据仓库(ODS)和数据仓库(DW)这两种环境下的数据索引是有差别的。在DW 环境
下,你要考虑销售部门是如何组织销售活动的。他们并不是数据库管理员,但是他们确定表内的
键信息。这里设计人员或者数据库工作人员应该分析数据库结构从而确定出性能和正确输出之间
的最佳条件。
2. 使用系统生成的主键
这一天类同技巧1,但我觉得有必要在这里重复提醒大家。假如你总是在设计数据库的时候采用
系统生成的键作为主键,那么你实际控制了数据库的索引完整性。这样,数据库和非人工机制就
有效地控制了对存储数据中每一行的访问。
采用系统生成键作为主键还有一个优点:当你拥有一致的键结构时,找到逻辑缺陷很容易。
3. 分解字段用于索引
为了分离命名字段和包含字段以支持用户定义的报表,请考虑分解其他字段(甚至主键)为其组
成要素以便用户可以对其进行索引。索引将加快SQL 和报表生成器脚本的执行速度。比方说,
我通常在必须使用SQL LIKE 表达式的情况下创建报表,因为case number 字段无法分解为
year、serial number、case type 和defendant code 等要素。性能也会变坏。假如年度和类型字
段可以分解为索引字段那么这些报表运行起来就会快多了。
4. 键设计4 原则
· 为关联字段创建外键。
· 所有的键都必须唯一。
· 避免使用复合键。
· 外键总是关联唯一的键字段。
5. 别忘了索引
索引是从数据库中获取数据的最高效方式之一。95%的数据库性能问题都可以采用索引技术得到
解决。作为一条规则,我通常对逻辑主键使用唯一的成组索引,对系统键(作为存储过程)采用
唯一的非成组索引,对任何外键列采用非成组索引。不过,索引就象是盐,太多了菜就篌了。你
得考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写。
大多数数据库都索引自动创建的主键字段,但是可别忘了索引外键,它们也是经常使用的键,比
如运行查询显示主表和所有关联表的某条记录就用得上。还有,不要索引memo/note 字段,不
要索引大型字段(有很多字符),这样作会让索引占用太多的存储空间。
6. 不要索引常用的小型表
不要为小型数据表设置任何键,假如它们经常有插入和删除操作就更别这样作了。对这些插入和
删除操作的索引维护可能比扫描表空间消耗更多的时间。
7. 不要把社会保障号码(SSN)选作键
永远都不要使用SSN 作为数据库的键。除了隐私原因以外,须知政府越来越趋向于不准许把
SSN 用作除收入相关以外的其他目的,SSN 需要手工输入。永远不要使用手工输入的键作为主
键,因为一旦你输入错误,你唯一能做的就是删除整个记录然后从头开始。
上个世纪70 年代我还在读大学的时候,我记得那时SSN 还曾被用做学号,当然尽管这么做是非
法的。而且人们也都知道这是非法的,但他们已经习惯了。后来,随着盗取身份犯罪案件的增
加,我现在的大学校园正痛苦地从一大摊子数据中把SSN 删除。
8. 不要用用户的键
在确定采用什么字段作为表的键的时候,可一定要小心用户将要编辑的字段。通常的情况下不要
选择用户可编辑的字段作为键。这样做会迫使你采取以下两个措施:
· 在创建记录之后对用户编辑字段的行为施加限制。假如你这么做了,你可能会发现你的应用程
序在商务需求突然发生变化,而用户需要编辑那些不可编辑的字段时缺乏足够的灵活性。当用
户在输入数据之后直到保存记录才发现系统出了问题他们该怎么想?删除重建?假如记录不可
重建是否让用户走开?
· 提出一些检测和纠正键冲突的方法。通常,费点精力也就搞定了,但是从性能上来看这样做的
代价就比较大了。还有,键的纠正可能会迫使你突破你的数据和商业/用户界面层之间的隔
离。
所以还是重提一句老话:你的设计要适应用户而不是让用户来适应你的设计。
不让主键具有可更新性的原因是在关系模式下,主键实现了不同表之间的关联。比如,
Customer 表有一个主键CustomerID,而客户的定单则存放在另一个表里。Order 表的主键可能
是OrderNo 或者OrderNo、CustomerID 和日期的组合。不管你选择哪种键设置,你都需要在
Order 表中存放CustomerID 来保证你可以给下定单的用户找到其定单记录。
假如你在Customer 表里修改了CustomerID,那么你必须找出Order 表中的所有相关记录对其进
行修改。否则,有些定单就会不属于任何客户——数据库的完整性就算完蛋了。
如果索引完整性规则施加到表一级,那么在不编写大量代码和附加删除记录的情况下几乎不可能
改变某一条记录的键和数据库内所有关联的记录。而这一过程往往错误丛生所以应该尽量避免。
9. 可选键有时可做主键
记住,查询数据的不是机器而是人。
假如你有可选键,你可能进一步把它用做主键。那样的话,你就拥有了建立强大索引的能力。这
样可以阻止使用数据库的人不得不连接数据库从而恰当的过滤数据。在严格控制域表的数据库
上,这种负载是比较醒目的。如果可选键真正有用,那就是达到了主键的水准。
我的看法是,假如你有可选键,比如国家表内的state_code,你不要在现有不能变动的唯一键上
创建后续的键。你要做的无非是创建毫无价值的数据。比如以下的例子:
Select count(*)
from address, state_ref
where
address.state_id = state_ref.state_id
and state_ref.state_code = 'TN'
我的做法是这样的:
Select count(*)
from address
where
and state_code = 'TN'
如你因为过度使用表的后续键建立这种表的关联,操作负载真得需要考虑一下了。
10. 别忘了外键
大多数数据库索引自动创建的主键字段。但别忘了索引外键字段,它们在你想查询主表中的记录
及其关联记录时每次都会用到。还有,不要索引memo/notes 字段而且不要索引大型文本字段
(许多字符),这样做会让你的索引占据大量的数据库空间。
--------------------------------------------------------------------------------
第4 部分— 保证数据的完整性
1. 用约束而非商务规则强制数据完整性
如果你按照商务规则来处理需求,那么你应当检查商务层次/用户界面:如果商务规则以后发生变
化,那么只需要进行更新即可。
假如需求源于维护数据完整性的需要,那么在数据库层面上需要施加限制条件。
如果你在数据层确实采用了约束,你要保证有办法把更新不能通过约束检查的原因采用用户理解
的语言通知用户界面。除非你的字段命名很冗长,否则字段名本身还不够。
只要有可能,请采用数据库系统实现数据的完整性。这不但包括通过标准化实现的完整性而且还
包括数据的功能性。在写数据的时候还可以增加触发器来保证数据的正确性。不要依赖于商务层
保证数据完整性;它不能保证表之间(外键)的完整性所以不能强加于其他完整性规则之上。
2. 分布式数据系统
对分布式系统而言,在你决定是否在各个站点复制所有数据还是把数据保存在一个地方之前应该
估计一下未来5 年或者10 年的数据量。当你把数据传送到其他站点的时候,最好在数据库字段
中设置一些标记。在目的站点收到你的数据之后更新你的标记。为了进行这种数据传输,请写下
你自己的批处理或者调度程序以特定时间间隔运行而不要让用户在每天的工作后传输数据。本地
拷贝你的维护数据,比如计算常数和利息率等,设置版本号保证数据在每个站点都完全一致。
3. 强制指示完整性
没有好办法能在有害数据进入数据库之后消除它,所以你应该在它进入数据库之前将其剔除。激
活数据库系统的指示完整性特性。这样可以保持数据的清洁而能迫使开发人员投入更多的时间处
理错误条件。
4. 关系
如果两个实体之间存在多对一关系,而且还有可能转化为多对多关系,那么你最好一开始就设置
成多对多关系。从现有的多对一关系转变为多对多关系比一开始就是多对多关系要难得多。
5. 采用视图
为了在你的数据库和你的应用程序代码之间提供另一层抽象,你可以为你的应用程序建立专门的
视图而不必非要应用程序直接访问数据表。这样做还等于在处理数据库变更时给你提供了更多的
自由。
6. 给数据保有和恢复制定计划
考虑数据保有策略并包含在设计过程中,预先设计你的数据恢复过程。采用可以发布给用户/开发
人员的数据字典实现方便的数据识别同时保证对数据源文档化。编写在线更新来“更新查询”供
以后万一数据丢失可以重新处理更新。
7. 用存储过程让系统做重活
解决了许多麻烦来产生一个具有高度完整性的数据库解决方案之后,我所在的团队决定封装一些
关联表的功能组,提供一整套常规的存储过程来访问各组以便加快速度和简化客户程序代码的开
发。在此期间,我们发现3GL 编码器设置了所有可能的错误条件,比如以下所示:
SELECT Cnt = COUNT (*)
FROM [<Table>]
WHERE [<primary key column>] = <new value>
IF Cnt = 0
BEGIN
INSERT INTO [<Table>]
( [< primary key column>] )
VALUES ( <New value> )
END
ELSE
BEGIN
<indicate duplication error>
END
而一个非3GL 编码器是这样做的:
INSERT INTO [<Table>]
( [< primary key column>] )
VALUES
( <New value> )
IF @@ERROR = 2627 -- Literal error code for Primary Key Constraint
BEGIN
<indicate duplication error>
END
第2 个程序简单多了,而且事实上,利用了我们给数据库的功能。虽然我个人不喜欢使用嵌入文
字(2627)。但是那样可以很方便地用一点预先处理来代替。数据库不只是一个存放数据的地
方,它也是简化编码之地。
8. 使用查找
控制数据完整性的最佳方式就是限制用户的选择。只要有可能都应该提供给用户一个清晰的价值
列表供其选择。这样将减少键入代码的错误和误解同时提供数据的一致性。某些公共数据特别适
合查找:国家代码、状态代码等。
--------------------------------------------------------------------------------
第5 部分— 各种小技巧
1. 文档、文档、文档
对所有的快捷方式、命名规范、限制和函数都要编制文档。
采用给表、列、触发器等加注释的数据库工具。是的,这有点费事,但从长远来看,这样做对开
发、支持和跟踪修改非常有用。
取决于你使用的数据库系统,可能有一些软件会给你一些供你很快上手的文档。你可能希望先开
始在说,然后获得越来越多的细节。或者你可能希望周期性的预排,在输入新数据同时随着你的
进展对每一部分细节化。不管你选择哪种方式,总要对你的数据库文档化,或者在数据库自身的
内部或者单独建立文档。这样,当你过了一年多时间后再回过头来做第2 个版本,你犯错的机会
将大大减少。
2. 使用常用英语(或者其他任何语言)而不要使用编码
为什么我们经常采用编码(比如9935A 可能是墨水笔的供应代码,4XF788-Q 可能是帐目编
码)?理由很多。但是用户通常都用英语进行思考而不是编码。工作5 年的会计或许知道
4XF788-Q 是什么东西,但新来的可就不一定了。在创建下拉菜单、列表、报表时最好按照英语
名排序。假如你需要编码,那你可以在编码旁附上用户知道的英语。
3. 保存常用信息
让一个表专门存放一般数据库信息非常有用。我常在这个表里存放数据库当前版本、最近检查/修
复(对Access)、关联设计文档的名称、客户等信息。这样可以实现一种简单机制跟踪数据
库,当客户抱怨他们的数据库没有达到希望的要求而与你联系时,这样做对非客户机/服务器环境
特别有用。
4. 测试、测试、反复测试
建立或者修订数据库之后,必须用用户新输入的数据测试数据字段。最重要的是,让用户进行测
试并且同用户一道保证你选择的数据类型满足商业要求。测试需要在把新数据库投入实际服务之
前完成。
5. 检查设计
在开发期间检查数据库设计的常用技术是通过其所支持的应用程序原型检查数据库。换句话说,
针对每一种最终表达数据的原型应用,保证你检查了数据模型并且查看如何取出数据。
6. Access 设计技巧
对复杂的Microsoft Access 数据库应用程序而言,可以把所有的主表放在一个数据库文件里,然
后增加其他数据库文件和装载同原有数据库有关的特殊函数。根据需要用这些函数连接到主文件
中的主表。比如数据输入、数据QC、统计分析、向管理层或者政府部门提供报表以及各类只读
查询等。这一措施简化了用户和组权限的分配,而且有利于应用程序函数的分组和划分,从而在
程序必须修改的时候易于管理。
世界上并没有成为高手的捷径,但一些基本原则是可以遵循的。
1. 扎实的基础。数据结构、离散数学、编译原理,这些是所有计算机科学的基础,如果不掌握他们,很难写出高水平的程序。据我的观察,学计算机专业的人比学其他专业的人更能写出高质量的软件。程序人人都会写,但当你发现写到一定程度很难再提高的时候,就应该想想是不是要回过头来学学这些最基本的理论。不要一开始就去学OOP,即使你再精通OOP,遇到一些基本算法的时候可能也会束手无策。
2. 丰富的想象力。不要拘泥于固定的思维方式,遇到问题的时候要多想几种解决问题的方案,试试别人从没想过的方法。丰富的想象力是建立在丰富的知识的基础上,除计算机以外,多涉猎其他的学科,比如天文、物理、数学等等。另外,多看科幻电影也是一个很好的途径。
3. 最简单的是最好的。这也许是所有科学都遵循的一条准则,如此复杂的质能互换原理在爱因斯坦眼里不过是一个简单得不能再简单的公式:E=mc2。简单的方法更容易被人理解,更容易实现,也更容易维护。遇到问题时要优先考虑最简单的方案,只有简单方案不能满足要求时再考虑复杂的方案。
4. 不钻牛角尖。当你遇到障碍的时候,不妨暂时远离电脑,看看窗外的风景,听听轻音乐,和朋友聊聊天。当我遇到难题的时候会去玩游戏,而且是那种极暴力的打斗类游戏,当负责游戏的那部分大脑细胞极度亢奋的时候,负责编程的那部分大脑细胞就得到了充分的休息。当重新开始工作的时候,我会发现那些难题现在竟然可以迎刃而解。
5. 对答案的渴求。人类自然科学的发展史就是一个渴求得到答案的过程,即使只能知道答案的一小部分也值得我们去付出。只要你坚定信念,一定要找到问题的答案,你才会付出精力去探索,即使最后没有得到答案,在过程中你也会学到很多东西。
6. 多与别人交流。三人行必有我师,也许在一次和别人不经意的谈话中,就可以迸出灵感的火花。多上上网,看看别人对同一问题的看法,会给你很大的启发。
7. 良好的编程风格。注意养成良好的习惯,代码的缩进编排,变量的命名规则要始终保持一致。大家都知道如何排除代码中错误,却往往忽视了对注释的排错。注释是程序的一个重要组成部分,它可以使你的代码更容易理解,而如果代码已经清楚地表达了你的思想,就不必再加注释了,如果注释和代码不一致,那就更加糟糕。
8. 韧性和毅力。这也许是"高手"和一般程序员最大的区别。A good programming is 99 weat and 1ffee。高手们并不是天才,他们是在无数个日日夜夜中磨练出来的。成功能给我们带来无比的喜悦,但过程却是无比的枯燥乏味。你不妨做个测试,找个10000以内的素数表,把它们全都抄下来,然后再检查三遍,如果能够不间断地完成这一工作,你就可以满足这一条。
21 gennaio
2005年的冬天特别的冷,两场大雪过后,我已经不再温暖了。
也许是自己抵抗力太差了把;也许是来的太突然了把。
要锻炼身体了。
19 gennaio
主管欣賞的人
在職場上,苦勞不會成功,其實企業最欣賞的人才,
是具有高度common sense的人,換句話說,
就是要work hard, work smart, work happy,
特質的A級人才。
.努力工作≠績效
是不是最努力工作的人就一定受到主管賞識呢?
有三個檢視標準或許可以提供 大家做為一個參考:
Work Hard, Work Smart, Work Happy。
你是不是很努力工作,但不快樂呢?這時或許可以檢核自己一下,
工作的方式是不是夠smart?
在這裡跟大家分享一個故事,或許可以引發大家一些思考與想法。
小芬與小美畢業於某國立大學企管系,同時進入一家中型企業,
擔任企劃專員的工作。小芬做事努力認真、守分務實,
常常自動留下來為公司加班,工作到很晚才下班。
小美呢?只見她每天嘻嘻哈哈,工作輕鬆又愉快,
每天都會主動去找主管聊天,給人一種跟主管感情很好的印象。
1年後,小美獲得主管升遷,委以重任,
小芬則只獲得象徵性的加薪鼓勵。這讓小芬非常不平,
認為小美工作又沒自己認真,只會逢迎拍主管馬屁,
憑什麼考績反而比她好?而且還受到公司的重用。
自己為公司付出許多,夙夜匪懈地工作,
反而落得一場空,於是遞了辭呈。
.少了一根筋
就在小芬工作的最後一天,總經理找小芬晤談。
剛好中秋節快到了,公司正在考慮該買什麼中秋禮送給客戶?
總經理說,「小芬,可不可以請妳到南門巿場跑一趟,
看看有沒有賣大閘蟹?」
小芬心裡很疑惑,不知道主管為什麼要她跑這一趟?
因為這並不是她負責的工作啊!但她還是乖乖地依照主管的要求,搭計程車到南門巿場。過了20分鐘,小芬回到辦公室,向總經理報告,「南門巿場有賣大閘蟹。」
總經理接著問她,「南門巿場的大閘蟹怎麼賣?算斤?還是算隻?」小芬一臉茫然,無法回答。於是又跑了一趟南門巿場,30分鐘後又回來報告,
「南門巿場大閘蟹算隻賣,每隻350元。」
總經理聽了之後,當著小芬的面,把小美找了進來,並吩咐小美,「麻煩妳到南門巿場去一趟,看看有沒有賣大閘蟹?」
小美馬上問總經理,「請問大閘蟹是有什麼用途嗎?」
總經理回答她,「中秋節快到了,打算送客戶大閘蟹做為中秋賀禮。」
小美立即出門。過了1個多小時,小美回來了。
一進門,就見她眉飛色舞地拎著兩隻大閘蟹。向總經理報告,「南門巿場有兩家攤位賣大閘蟹。第一家的大閘蟹,每隻平均4兩重,每隻賣350元。第二家的大閘蟹,每隻平均6兩重,一隻550元。我建議,如果總經理自家食用可以買4兩重的,肚白、背綠、金毛,看起來很新鮮。如果總經理要送人,我建議買6兩重的,看起來比較有份量。我各買了一隻帶回來給總經理參考。」
.做事Smart有方法
聽完小美的報告之後,總經理轉頭問小芬,「妳看出妳們之間有什麼不同了嗎?」
小芬一副恍然大悟的神情,趕忙點頭表示她明白了!
總經理向小芬進一步說明,「一樣是去南門巿場看看有沒有賣大閘蟹,妳們蒐集回來的巿場情報與態度截然不同。小芬,妳很認真沒有錯,但是妳並沒有思考這項任務的需求是什麼?只是一個口令一個動作,得來來回回好幾趟才能把一件事情做好。而小美呢?不用我多交待,一次就把事情搞定,她不僅蒐集了完整的巿場情報,甚至也提出建議與分析,協助我做為判斷的參考。」
.苦勞不會成功
小芬聽了不禁自慚形穢,她最感慚愧的是,為何她與小美是最好的同學,
居然沒有學習小美的做事優點,暗地嫉妒她。
同時她也很謝謝總經理為她上了一堂寶貴的一課,點醒她的負面思維。
在職場上,苦勞不會成功,其實企業最欣賞的人才,
是具有高度common sense的人,換句話說,
就是要有work hard, work smart, work happy特質的A級人才。
這樣的人才能快速掌握主管的需求與期待,為公司開創更大的格局。
The race is not to the swift or the battle to the strong,
nor does food come to wise or wealth to the brilliant or favor to the learned:
but time and chance happen to them all.
快跑的未必能贏,力戰的未必得勝;
智慧的未必得糧食,明哲的未必得資財,靈巧的未必得喜悅;
所臨到眾人的,是因為「時間」與「機會」。
親愛的好友們!你們學到了嗎?
你我是不是只懂得做個『努力工作、認真、守分務實』的人呢?
13 gennaio
从前从前有一个尼姑跟一个屠夫是好朋友
尼姑天天早上要起来念经
而屠夫天天要起来杀猪
为了不耽误他们早上的工作
于是他们约定互相叫对方起床
多年以后....
尼姑与屠夫相继去逝了
屠夫去上天堂了
而尼姑却下地狱了!!
why??<
05 gennaio
童心:
无论你有多老,你的心不能变老。
音乐:
如果没有音乐,你的人生将会乏味无比。
浪漫:
偶尔浪漫一下,那种感觉就像一只小鸟在空中飞翔吧。
优雅:
何必要装的粗鲁呢,优雅一点总是好的。
沉思:
在你有一肚子火要发之前,先给自己10分钟沉思一会儿。
驰骋:
如果真的累了,就变成一只蝴蝶逃开一会吧,不要让自己太累。
纯洁:
现在的社会已经够混浊了,纯洁真是不容易做到呢。
勇敢:
做个勇敢的精灵,不惧狂风会撕碎你的翅膀。
可爱:
我相信,你会因为可爱而美丽。
29 dicembre
人生就像一个没有Backspace键的浏览器,一旦走到下一步,你就无法再回头。
不够冷静的头脑像没有加装风扇的CPU,一不小心就会造成重大的错误。
虚伪的人就像RE-MAKER过的CPU,把性能不正当地提升,但最终会被识货的人看穿。
不论你的爱情多么神圣、多么完美,它都会受到其他一些负面因素的影响,就像再优秀的MODEM的传输速度都会被电话线路所制约。
婚姻就像光盘一样脆弱,海誓山盟的承诺只有用心呵护才不会变;一旦发生摩擦,不论是光盘还是婚姻,其质量都会受到影响。
婚外恋就像一个带着“I LOVE YOU”病毒的应用程序,一旦运行在你的生活进程中,不仅将影响婚姻进程,并可能导致整个系统瘫痪。
电脑的升级部分主要是内部核心,人也是一样,容易落后的不是你的衣服,而是你的思想观念和能力。
在这里给同胞们一点忠告:
TO男同胞们:有些女孩很漂亮,就像高级彩色激光打印机一样,但你不仅仅要考虑买下它的花费,更要留意日后耗材的消耗,你微薄的薪水是否能承受。
TO女同胞们:有些男人就像出售电脑的奸商,在把他自己卖给你之前说得天花乱坠,并承诺一切售后服务,但如果你真的买下,很不幸,那就该你为他服务了。
记住了人生就像一个没有Backspace键的浏览器,一旦走到下一步,就无法再回头。愿我们都能正确地走好每一步…………
24 dicembre
前几天我的一个朋友接到一个短信:内容是你中了大奖,奖金20万现金,联系电话等。朋友没有理会,现在这事多了都知道是骗局,过了一阵朋友的手机响了,一个南方小姐问:先生你收到中奖通知了吗?朋友说收到了,小姐又说:请把你的银行卡的帐户告诉我们,我们把奖金汇进你的卡里。朋友一想给你个帐号看你玩什么把戏,朋友在招商银行有个哥们,于是就给她一个招行一卡通的帐号。十分钟后,朋友的手机又响了,南方小姐说:先生你的奖金已经存进你的帐户里了,请你查询一下,朋友用电话银行查询,果然进了20万。朋友高兴极了,白捡20万。30分钟后南方小姐来电话,带着哭腔对朋友说:“先生!对不起,由于我的疏忽忘了抵扣奖金的个人所得税了,20万的20也就是4万元,现在公司让我个人赔偿,请您把4万所得税汇回来好吗?求您把4万所得税汇回来好吗,求求您了!”朋友一想也在理,也有可怜小姐之心,一想卡里还有钱,于是就到招行汇款,忽然他想到招行的哥们,就找到在招行的哥们,让他查一下,招行的哥们一查,是用其它行的支票汇过来的,虽然钱到帐,但当天入不了帐,也就是说20万今天取不出来,如果对方今天撤票,20万就没了,朋友一听吓的直吐舌头,差一点4万就没了。果然下班前那笔汇票撤销了。如果没有银行的朋友,如果不是专业人士,如果怕别人知道中奖,这个骗局一定会成功。
这是他人亲身的经历,一早来就赶紧把这讯息分享给大家,请各位告诉大家,现在的诈骗集团手法实在太多了.....稍不注意,可能您的血汗钱就~~~~~~~byebye~...昨晚礼拜天(1/11),约莫八点多我正在帮小儿子洗澡,听到电话铃响就让儿子泡澡,我出去接电话。”请问蓝小姐本人在吗? ” 一个约四十来岁的妇人...“请问您哪里找?”对于陌生的声音我总会持保留态度..“您是蓝小姐本人吗?我这里是上海银行树林分行值班人员。”“我是,请问有什么事?”“我们刚刚在分行的提款机里收到一张以您的资料制成的伪卡,可能是歹徒太紧张了连输三次密码错误才吃掉,为了维护您的权益,刚刚我们已经向树林分局备案了,需要您亲自再去备案,这样你了解吗? ”“喔...了解,不过,我没有上海的卡,请问他那张伪卡是哪家的?”“....嗯...因为是伪卡,所以我们只能从背面的条码读出是你的资料,哪家的卡我不清楚,你还是马上打电话去树林分局备案,保障自己的权益。刚备案的联单号码是c189,你记下来,你打去树林分局就先报你的联单号码。树林分局的电话是8861****,你记下来了吗?要马上打喔。”“这样啊..好我记下来了。” “要马上打喔,再见。”接下来,我马上打104查号台,查出树林分局的电话是286*****,根本不是对方所留的号码,不过我还是打到分局,警局的人一接,我都还来不及说明,警察先生就脱口而出:“那是诈骗集团,千万不要打那个电话。” 真的很可怕....听说现在的诈骗手法已先进到...对方已掌握有你的帐号...当你打他要求的 电话,电脑就会自动连线,变成自动转帐....你的钱就会自动滚到别人的口袋了.......所以,小心,小心....这年头,真的要特别小心喔~~~~~~
“ 男主角和女主角在车上争吵着,迎面一辆大卡车飞驰而来...... ,还好没有出车祸 ”
这是天下无贼的一个镜头,而这个镜头上引起我注意的是卡车上的几个大字 ------- “长城润滑油”
哈哈哈,一看就是广告。据说广告费还不少啊。
抢钱拉
这两年来雨后春笋般地冒出二三十家做报表工具的公司,统统号称能处理中国式报表,大概是这中国报表复杂得都世界闻名了,但凡能搞得定中国的报表,那也就没什么搞不定的报表了。弄到后来有好些所谓的报表只要能在格子里摆条斜线就敢说能对付中国报表(这也太小瞧祖国文化了),而且老外也开始扬言适合于中国报表了,这时髦,不赶怕是不行了。
可话说回来,这中国的报表确实够复杂、巨费劲。用户拿出一撂纸往咱面前一堆:“就照这个做吧”,立马头就晕了,随便选一张搞个两三天是家常便饭,运气坏了折腾一礼拜也不是多罕见的事,手里握着世界排名前三的高档武器(这里不方便点名批评,大家心领神会吧)依然搞得人垂头丧气,末了还是得拿出看家工夫——写代码!谁让咱是程序员呢,就这命呗。
那到底啥才算是中国式报表?中国的报表到底复杂在哪里?号称能对付中国报表的工具到底灵不灵?中国人是不是吃错了什么药非要把报表搞这么费劲?
我们就来胡乱聊聊中国报表的这些闲事。
我们先来研究一下中国报表的特点和当前报表工具的问题。
先从样子上看,中国人的报表好象很少有没有格线的,不仅有格线,还恨不得搞它三五层,大格套小格,更不要说大伙津津乐道的斜线了。可人家老外的报表真地很少有线哟,就那么几个数对得倒也整齐。不过,老外的表层数不多,不容易看花眼,中国的表头比较乱,没有格线容易看走眼的,所以格线确实是非常必要的。
格线既然是为了令数据对齐的,那线本身更是应当横平竖直、一贯到底,小学生画表都是拿尺子比着,一气画老长一条。可老外的武器中却没顺便带上尺子,只是把一些数连同其框框摆来摆去,美其名曰拖拽,号称只要用鼠标简单拖拽就可画出报表。
这么一来,一条长线就要靠十几个甚至几十个小框框拼出来了,一个挨一个。哎,本来一笔就画得出来的线,要堆上几十段,你说烦不烦?单层的还可说,偏偏我国人民喜欢一层套一层,这样就得上下左右全面对齐,这么多小框框指不定哪个不太老实偏出去一点点,直线就变阶梯,中国表还经常特宽,搞得顾了左顾不了右,哪天用户心血来潮要加减几个框框,那可累死人了(用户反正不干活,眼不见心不烦),而且这种纯粹的机械劳动叫我等来搞,真有愧于国家多年的栽培,此时那三字经是不由得要脱口而出的。这还没算完,辛辛苦苦画整齐的表,怎么打到纸上又不齐了,敢情这东西还和分辨率相关,哎,这打印机何苦要比屏幕分辨率高这许多。
这种所谓先进的“拖拽式”其实可以用来画任何东西,是一个一般性的图元编辑器模型,半点也没有体现出表格的规律性,什么都能画,可什么画起来都不大方便。
老外的不行,国人造的如何?可惜,绝大多数国货都在抄老外,谁叫人家发达呢,咱也分不清好不好,都给抄来了。
难道就没什么可使的兵器了?有!当然有,光是摆样子又没多难,人家老外也有这种兵器,而且好使得很。
那就是大名鼎鼎的EXCEL了。EXCEL采用网格线把格子围出来的画法,配合以合并格和边框,好比给大家配上尺子和笔,这下爽了,一个看似复杂的表格三下五除二就搞定了。EXCEL的画法充分体现了表格的规律性,所以特别方便,方便得连用户自己都会搞了。
这下又坏事了,用户太喜欢EXCEL了,于是要求所有报表都要能生成EXCEL的格式,更有甚者,以后不再给咱一撂纸了,给咱一批EXCEL文件,扬言要咱直接读进去,省得再画。
这可更苦了用老外工具(或抄老外的国货)的人,拖拽式和EXCEL的搞法完全不同,定要生成EXCEL文件的话,大都会丧失格式(国货大抵如此),个别使了大劲的可以搞得很象(老外的一般有这个本事),又还是依赖于您的对齐工夫,稍有不慎,嘿嘿,一行变N行。至于读入EXCEL文件,那更是想都别想,还不如打到纸上再对着描着舒坦呢。
那咱干脆直接就用EXCEL好了,不用这些罗里巴索的工具了。哎,这还是有点不大行,EXCEL的格式上是顶呱呱没得说,可没什么数据汇总方案,基本上没法从数据库中读出数据自动产生报表,这毕竟是咱用报表工具的主要目的,否则又得编程序往格子里填数据。
刚才说了,绝大多数国货在抄那种“拖拽式”的老外,那剩下的小部分就在抄EXCEL了,同样抄得倍儿象,没什么数据汇总功能,只能画画样子,也还是没法用。
不过,也真有被这可恶的“拖拽式”折磨过头的,自已编程去准备数填入EXCEL(或类似产品)。这现象其实也还得怪这些报表工具不争气,不仅画起来费劲,统计汇总的本事也就比EXCEL强一点点,离中国报表的要求差得远。这就是我们要谈的第二个方面,也是中国报表真正最复杂的地方。堆框框虽费劲,可有道是只要功夫深,铁杵磨成针,但统计汇总本事不行的话那就没治了,无论功夫有多深,木杵总也磨不成针。
数据统计方面的问题要比报表样式的问题多得多,也严重得多,要分几个方面来研讨。这些研讨主要且只能针对拖拽式的报表工具进行,毕竟这些东西还算有点自动化本事。
中国报表统计方面第一个重要特征是多数据源。
所谓多数据源是指同一张报表的数据会来自多个不同的数据表或视图,甚至来自多个不同的异构数据库!这东西空口说有点费劲,咱瞧上俩例子。
1)人员信息表
姓名 性别 年龄
政治面目 学历 职称
家庭住址
家庭成员
称呼 姓名 性别 年龄 单位
没有特殊情况下,智商正常或以上的人都会在数据库中设计两张数据表来保存这个表格中的数据,那么这张表格的数据就会同时来自这两个表。
2) 成本销售表
月 购进货物 销出货物 余额
烟 酒 茶 糖 烟 酒 茶 糖
期初
1
2
3
合计
一般为了业务系统处理方便,购进和销出信息在数据库中也会是两个数据表,这张报表中不仅有两组来源不同的数据,而且之间还要运算(余额)。
可惜,不知怎么搞的,这些老外和抄老外的武器全都是单数据源的。不论你的数据来源(那SQL语句或存储过程)搞得多复杂,到了报表这一端都必须变成单个的二维表了。
那这些工具是咋对付多源问题的?
对于第一张表,上下部分格式完全不同,只能采用子报表的法子了, 也就是把下半部分造成一个子表贴进去。这样倒是解决了多源问题,可新问题又来了,首先让原本就极难对齐的格线变得更难对齐,目前这个还算简单,如果搞上三五个子表横七竖八的排起来,每个子表都不知会变得有多大(表会根据数据库中数据扩展),那就要充分考验您当初平面几何念得如何了;其次主子表之间除了简单的参数传递外,互相没法沟通,要想把几个子表中的数加一加,对不起,您得自个儿呆一边重算去。所以,子报表是能不用就甭用的。
而第二张表,样子看起来倒不复杂,用不着搞子表。不就俩数据表吗,咱会叉乘呀,写个麻烦一点的SQL不就得了吗。那是,俩表时这么搞一下还行,可指不定会有几个源呢,中国表中有七八个数据源的并不罕见,甚至十几个的也不过份,您总不能把这一大堆表都让可怜的数据库去叉乘吧,如果真这么搞,算一个表您就可以沏杯茶歇一下,茶喝完了还不定能算完;而且,这SQL越写越复杂,和写代码好象也没什么差别了,那天书般的SQL语句要是出点错谁来查(SQL可没法写注释,笔者就见过长达三页纸的SQL,那确是天人所书,真亏数据库居然算得出来)。这还不算,如果这几个源来自多个不同的数据库那可就彻底完了,想喝茶都没戏了。
怎么办?只好祭出最后的法宝——写代码!咱毕竟是程序员嘛,还会写存储过程准备中间数据表,无论多少源、来自多少库,只要肯写代码,统统搞得定。哎,可这么搞,还要这些报表工具干吗呢?
怎么样,折腾得够呛吧,不过,您可别松气,麻烦人的还在后面呢。
中国报表的第二个重要特征是分片,与多源相关,但又不完全一样。多源一般都会是分片的,但分片却不一定是多源的。
还是上面这两个例子,两个报表都很明显地分成了两片,每片都有自己独立的规则,很难统一成一种规则处理。而我们手中的报表工具,如果不考虑采用子报表的话(其危害在上面已经说过了),都要求报表有统一的规则,整个报表只有一片可以重复的条子(细节区和相邻的分组区),因为是单源的,想当然地以为只要一片重复区就够了,理论上就不可能做到分片规则了。
但中国报表中分片现象太常见了,同一批数据也可能按不同的主题统计汇总,比如人事表中并列着按民族划分再按学历划分。事实的情况还远不止分作两片,常常是竖着五六片,横着也是五六片,整个报表乘起来就有二十五六片。而且片与片之间又不是完全独立,横向的分片在纵向规则却又是一致的,反之也是如此,这样既算想搞成子表,嘿嘿,怕是也不大容易,每个分片的表头都要重复编排,对齐则更是要命。
如果运气好,虽然分片了,但整个表的样式看起来还是一致的(比如上面的第二个表),那还可以使出咱最后的杀手锏——写代码!咱写程序把分片的数据搞成一片不就完了,那还是那个话,咱花钱买这这报表工具干吗来了?
运气不会时时都好,如果碰到那种上下(或左右)几个分片中分组层数都不一样的表,那就连最后的法宝都不管用了,就算代码能把数给算好,可格子却拼不出那种上下不同的样子,这会儿您就会特别想念EXCEL了,至少样式是可以很随意的,写代码也就可以搞定了。哎,直接做是做不出来了,用子报表也太恐怖了,想法和用户商量吧,搞表格简化一点吧,别老搞这么怪的样子,我做得烦,您看着也晕吧,咱改简单点吧。
够烦心了吧,嘿嘿,您可甭急,分片问题这才说了一半。
具体到每个分片也不是省油的灯,不象老外弄得那么简单,一下把所有的数都列出来,或者把所有的分组一个不落一个不重的列出来,这种搞法我们叫做“完全划分”。对应的就还有“不完全划分”,也就是分组中并不是把所有出现的情况都列出来(这种很常见),而且还可能重复列出(这个相对少见些)。比如我们按民族划分人员时,不大可能把五十六个民族全来一遍,一般也就是列几个大的民族再加个其它。比较典型的不完全划分现象就是固定行列,无论数据库中有多少记录多少分组,咱就只关心这几种情况,表格永远只有这几行(列)。
这可奇了,会变多的行列得能做出来,固定的还搞不定吗?嘿,还真是这么回事,老外这些东西天生就是和数据库绑定的,固定行的倒不是搞不出来,可又要写代码或者复杂的SQL去准备数据了,象著名的资产负债表,用这些报表工具去搞简直就是有点摧残生命了。
而且就算是会变动的,这些工具也还有个行列不对称的问题,由于和数据库贴得太紧,大家只见过记录数会变的数据表,都没怎么见过字段数也会变的数据表,于是这堆工具也就专心处理行方面的变化了,拒绝去处理列数会变的表,后来总算有了一些打补丁的交叉表模板,能对付点事了,但总是用起来不那么得心应手。可咱中国报表才不管这些,想往下长就往下长,想往右长就往右长,咱没觉得行和列有那么大的差别,至多列数可以少一点,总不能不让咱动呀。这么一搞,只要碰到变列的交叉表,除非特别规整的,这些大牌武器就又要虾米了。
中国报表统计方面的第三个复杂点是格间运算,特别是跨行组的运算。
要统计就要有运算,所有的报表工具都提供了计算汇总的功能,运算只有两种,一种是行内各列之间的运算,另一种是针对某组(或全体)所有数据进行的汇总(可能带条件),两种运算可以组合。但是,在中国的报表中只有要时间序列的,多半就要涉及到比上期、比去年同期之类的运算,这种运算跨行甚至跨组了,这个本事,咱手上这些报表工具又没有了。这是有原因的,大体这类工具都和数据库的概念匹配得很好,而数据库的行是没有次序的,搞不清谁是谁的上一行,比上期就没法定义了,比去年同期这种跨组运算更是想不明白了。为了解决这些问题,有些工具添加了一些引用上行或累积值的特殊函数,但跨组运算依然没法处理,您只好再一次使出编程序的法宝,自己写代码把数据准备好吧。
这种比较有规律的东西倒还不算太难办,编程序准备数据或是写个复杂些的SQL都还是可以搞定的。但中国表中常常还会有些独独的格子,其运算方法和谁都不搭界,或是胡乱从表格中东西南北挑几个格子加减乘除一番,或是干脆自个儿到数据库中再搞一句SELECT算一把,完全与其它格子之间无规律可循,整一个十三不靠。这下可就费大劲了,不是在后台写点程序准备好数据库完了的,要生成完表格再编程序计算出这些数填进去,这种搞法一般就得采用报表的脚本或者宿主开发语言来写代码了,弄得代码满天飞,维护时找不到北。
这三个较大的数据统计问题已经把大伙折磨得差不多吧,其它相关的还有一些次要问题,比如参数和宏的引入、交叉表的表头向右对齐问题等等,咱就不细说了。
不过,事还没算完。中国报表还有填报的要求。
所谓填报,顾名思义,就是填了再报,那报表不是统计汇总完了就完了的,还要能填能改,改完的结果还可以再存起来,咱从小不就常常填表吗?可老外哪里想过这种问题,造出来的工具统统没有这个本事,人家觉得报表是报表,就是不可改的,填的表是另一种东西,根本不能叫报表。但咱中国人天生就认为表都是可以填的,这世上哪有不能填的表,那还叫表格吗?
说得也是,人家EXCEL就可以填,而且填着还方便得很,搞得按照EXCEL抄的国货也统统有填的本事。不过,话说回来,这些工具还是有上面说的问题,没有数据模型,填完的数不知怎么写进数据库,于是常常只能放进文件中(就象EXCEL文件本身),等着您再编程序处理吧。
填报功能说起来其实也挺复杂的,首先要允许表格和数据库字段的随意对应,我可能整表一条记录,也可能一行一条记录,甚至可能一格一条记录(交叉表填写),这几种情况还可能是组合出来的,同一张表一下子写进好几个数据表。填的过程中还应当有自动计算能力(比如EXCEL就很强了),提交时应当有合法性的检查功能,看看您填的数是否合理;更有甚者,中国要填的表经常是一套一套的,十几张之多,那不是一时半会儿填得完的,咱得下载下来回家慢慢填,这又需要多页填报或离线填报的功能。这每条功能搞起来都没那么容易,够狠吧!
除此之外,中国报表还有不少折磨人的小地方,特别是在打印输出方面,比如一张纸上打印几个小票据,横向分栏,横向分页时左表头的重复,末页补足空行,票据套打等等,这些比较头痛但还不算什么根本的问题,这里就不仔细评说了。
还有一个和中国报表特征没啥关系但是程序员常常碰到的头痛问题,就是产品的集成性。
在国内做应用开发,报表只是应用的一个部分而非全部,报表总是要被集成到应用系统中去,如果某个报表工具能力超强,但却不可被集成,那也是没啥意义的。
考虑到当前国内应用开发的现状,我们只研讨基于J2EE机制下的B/S应用的报表集成。
现在流行的报表工具几乎都是独立服务器形式。咱可能资质愚钝,想了许久,楞没想出独立服务器的半点好处来,倒是想出一大堆坏处,下面就来批判批判:
报表服务器与应用程序不在同一个进程空间内,数据沟通都需要通过网络协议进行,即算是同一台机器上,也要把数据传来传去,无端浪费时间降低性能;这种独立的服务器常常也还自己一套用户权限管理机制,设计得还很复杂,咱的程序必须向这个规矩上靠,可这套规矩从来也不会够用,应用系统的用户管理啥时候也没那么规整过,就乖乖地按它家设计的样子来,比如您何曾见过这样的系统,把应用系统中的柜员、科长、局长这种业务角色建立在ORACLE的用户上?这种费了劲又严重影响集成度的东西其实不搞也罢,常常因此浪费巨多的时间还是和应用接上不口。
然后还有问题,独立服务器又没法充分应用服务器的本事,比如数据库连接就不可和应用系统的其它部分共享,非要独独地自己搞一摊,更过分的是集群能力,也还得听命于这个报表服务器。靠,我就不信,Weblogic的平衡负载能力会比你的报表服务器要差劲?人家专吃这碗饭的会搞不过你?可没办法,也只好由着它折腾了。还有布署方案,本来所有的程序数据打个WAR包很方便就上去了,可它偏要与众不同,要独自战斗,还是搞得咱没脾气。
想来想去,估计美国人可能不大需要被集成的报表工具,所以老外的产品也不是为了被集成而设计,这也就情有可愿了。可叹的是,国人抄老外时也没怎么想想,大多一古脑地把体系结构也抄了过来,特别是海归派的新兴企业,抄得有鼻子有眼的,费了老劲还没落到好;有系统集成经验的国产报表厂商就还稍好一点,没去费那没用的劲。
牢骚差不多发完了,这下您该知道中国报表到底是怎么个麻烦法,为啥我们有了国际水平的先进武器依然过得很衰。这些流行的工具名头虽响,确实是极其不适合中国报表的,号称能适应中国报表的大都是胡说八道,赶赶时髦而已。
是不是中国人真地吃错了什么药非要把报表搞这么复杂,以后有没可能简单起来?
报表工具厂商中有一个较普遍的说法是中国现在的应用水平太差,用户都不懂信息化,所以造成了报表复杂,一句话,就是咱的需求错了,咱不够高档,人家高档的美国用户就不用这么复杂的表格。
、听起来有点道理,其实是胡扯!明明是自己做不出来,偏偏要说用户的需求不合理,象是《笑林》的那个笑话,和尚念错了经却指责人家死错了人,真是岂有此理!
说老实话,由于没有信息化经验而设计出不合理的报表当然也是存在的,但大部分情况下即使信息化程度已很高,那报表还是复杂得很,而且信息化程度越高,EXCEL使得越熟,那报表就越复杂。比如银行,在中国算是信息化进行最早的行业了,您去瞧瞧银行的报表,嘿嘿,晕死人不赔命的;再如日本人,信息业够发达了吧,那报表还是那样复杂得没商量。至于说美国人的表为啥不太复杂,咱没在美国生活过,还真一下子搞不清。不过,中国的报表复杂是很有道理的,各项信息在表上一目了然,就是省事。所以笔者认为,大概是东方文化传统的因素让中国报表复杂下去,如果真是这种原因,中国的报表还将一如既往的复杂下去,怕是没什么简化的指望了。
所以呢,不要寄希望于报表会变简单,那会被你的竞争者置于死地的,还是努力想法怎么解决这些问题吧。