首页 > 开发 > 综合 > 正文

《SQL Story》摘录五——关系真相

2024-07-21 02:09:04
字体:
来源:转载
供稿:网友
中国最大的web开发资源网站及技术社区,
 
关系的真相

长期以来,我们习惯了称关系型数据库中的表为二维表。因为它有行和列,很容易我们就可以把它同一个二维平面联系起来,但事实上,这并非关系型数据库的初衷,也并非符合关系模型的设计。其实长久以来,我对此也只有一个很模糊的概念,对平面表的观点虽有怀疑,却一直无从验证。直到有一天,翻出一本老书——《关系数据库》(石树刚、郑振楣编著,清华大学出版社,1993年),这本老书没有什么流行的新噱头,却满满当当地净是数学理论。这本书读起来并不是很诱人,不过的确很严谨,澄清了我的很多不明之处。也激励我找来各种权威材料重头学起。薄薄一本书,定价只有9.9元,想想这应当是我在上学时,从旧书摊上买的,可能当时只花了不到五元钱。这肯定是我买的性价比最高的一本书了。

在此,我不想从别人书中抄出大段原话,拼出一篇文字,有这工夫还不如上网回贴子更有成就感,我宁愿将我的心得,用并不严密,但尽可能易懂的语言写下。让朋友们先对关系模型有个基本概念,使众多像我这样非科班出身的读者多少了解一下事实真相,不至于在工作中有所不便。如果你想真正掌握关系型数据库的数学模型,请读一读这本不流行的老书《关系数据库》。当然,还有很多新近的正规教材也写得很不错,比如现在在我手边的《database system concepts》(机械工业出版社)和《sql-3 参考大全》(机械工业出版社)。前两本写得更严谨一些,后一本是译得不太好,有些关键地方读着莫名其妙,不过总得来说还是本难得的好书。

言归正传,现在我们说说关系型数据库到底是怎么一回事。我们先看一个表:

x y z

------------------

0 0 0

1 1 1

0 0 1

0 1 1

……

这个表存储一个三维空间内的一些点。我们可以很清楚地看到,每一个完整的行,才代表一个点。仅定位某行某列,它并不能表达这个表所定义的信息结构。当我们向这个表中插入或删除数据,它仍代表三维空间内的点集。但如果我们增加一列t(time)呢?那一切全变了,它不再是三维空间了,现在,这个表中存储的是四维的信息了(读过相对论的朋友应当了解,相对论中的时空就是一个四维坐标系)。删除一列呢?比如z列,现在我们面对的就是x-y 平面了,这是一个二维坐标系。也就是说,在表中删除或增加或修改若干列,并不会改变这个表所代表的意义。而修改或增删列,就会改变表的结构,表所代表的意义也就不同于以前了。表的行和列,并不是平等的!我们不能简单地把它理解为一个平面!相反,我认为,将表的结构理解为一个代数空间更合适,这样,表中的每一行是这个代数空间中的一个点,那么当前表中的信息就形成了这个空间中的一个点集。当然,这个集合还可有其它的约束条件,下面我们从关系模型说起。

在严格意义上的关系模型中,一个关系模式,包括关系名、有限属性集、属性值域、属性列到值域的映射、完整性约束和属性间依赖。对应数据库中的结构,通常一个关系模式对应一个或多个表和视图。这些表和视图有其各自包括的列,而列有列名、列的数据类型、表和视图的主键约束、外键约束、检查、断言、触发器(在sql server2000中,已可以在视图中定义索引和触发器,再加上视图本身的 sql脚本,视图以可以定义为一个完整的关系模式)。一个简单的关系模式可以只由一个表构成,而多个元组(表或视图)组成的关系,其相互的关联由外键和触发器来完成。在这个定义中,关系中的各个列(也就是说关系的模式)可以有很强的依赖性。比如某些列有主键约束,另一些列有引用外键。而行与行之间(也就是说关系之间)的依赖只存在于两种情况——外键和触发器。其中外键可以表达为模式上的(也就是列之间的)依赖。例如以下订单系统,它由客户表,订单表和

create table customers(

customerid int not null,

firstname char(20),

lastname char(20),

city varchar(30),

constraint pk_customer primary key(customerid)

)

create table goods(

id int not null,

name char(20) not null,

number int,

price money,

constraint pk_good primary key(id))

create table orders(

orderid int not null,

customerid int not null,

orderdate datetime,

constraint pk_order primary key(orderid),

constraint fk_customer foreign key (customerid)

references customers(customerid))

create table items(

itemsid int not null,

orderid int not null,

number int not null

constraint pk_item primary key(itemsid),

constraint fk_good foreign key (itemsid)

references goods(id),

constraint fk_order foreign key (orderid)

references orders(orderid)

)

以上一表中,一位客户可以有多张订单,订单的订户依赖客户表。一张订单可以有多个条目,明细条目又依赖于订单和商品的存在。这四个表就构成一个关系模式,四个表都有其主键,表中的其它列依赖于主键列。表之间的外键引用则构成了表之间的依赖关系。由此联接起了整个模式。每一个完整的订单,包括orders表中的订购信息和items表中的明细,形成一个关系。而一个用户和他的订单,又可以形成一种新的关系,这些关系的模式,可以由sql语句来表达,这里不详细讲了,朋友们可以试一下,很简单的联接查询而已。我们可以看到,这个典型的关系中,信息的内容之复杂,远远超出了“几个二维平面表”所能定义的。“带有强约束条件关联的若干代数空间点集”可能更好一些。甚至,我们还可以在其上定义更强的约束,比如用一个触发器保证用户的订购数在某一范围内。当我们增删订单,存货甚至客户时,由于强有力的约束存在,保证了每个关系仍是完整的。可列的定义本身就是关系模式的一部分,如果我们改变或增删了列,修改的是整个模式。至少一个代数空间,被我们改变了。这也就是行和列的区别。当然,只定义一个表,不给它加以任何约束,在技术上是允许的,但这样的表不能称为一个关系。它甚至不能保证最基本的关系完整性。如以前的文章所示,这样的表轻易就可以插入重复数据,而这些不能互相区别的数据并不能给我们更多的信息。这种没有约束的表在实用中应当严格限制于临时表,不应在其它任何场合出现。

希望读了这篇文章的朋友,能够不再犯我当初常初的错误,建立一个又一个没有任何约束的表,存入不可靠的数据。我们应当把信息的结构和关系模型直接表达在数据库的设计中,这才是关系型数据库的意义所在。这一次几乎没有可执行的代码,可能读者们会有意见。不过真心祝大家能理解我的意思,在关系型数据库的世界中更轻松自如地工作。如果您有批评、表扬、指导,我在这里专心地听取,谢谢您的支持。我在书中专注于sql server 和interbase,希望有oracle或db2等其它数据库系统的高手与我合作,完成本书的不同版本内容,与我分享劳动的艰辛和成功的喜悦。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表