通向T-SQLDML 3级的阶梯:在SQLServer中实现关系模型
这篇文章来自于阶梯系列:到T-SQLDML的阶梯。这一阶梯将为您提供如何使用SQLServer的Transact-SQL(T-SQL)方言来处理SQLServer表的数据。DML是一种数据处理语言,是用来处理一些数据的语言。它包括选择、插入、更新和删除语句。这个阶梯将会提供一些SQL语言的历史和一些集合论的概念。每个级别将建立在以前的级别之上,所以在你完成之后,你将很好地了解到怎样从SQLServer中选择数据和修改数据。
在这个阶梯的前几个级别中,我为你提供了有关SELECT语句的基础和SQL语言的历史。这些基础级别让你了解到如何检索数据,以及SQL如何随着技术的发展去变化的。在这个级别之上,我将探索如何实现简单的关系模型SQLServer数据库。在创建数据库之前,首先让我分享一下有关关系模型创建者的一些历史。
关系数据建模之父。
关系数据库设计最早在1970年由Edgar F. Codd提出,并且他发布一篇文章“一个关系模型数据的大型共享数据银行”。Codd开发建模理论的时候在IBM工作。那时IBM没有更快地跳到在科德的数据建模的概念,所以无法提供关系数据库引擎和开发Codd新关系数据建模理论。Codd的关系模型概念现在是用来在SQL Server和其他关系数据库引擎创建关系数据库的框架。
Codd出生于波特兰的英国岛,研究数学和化学,后来加入英国皇家空军,成为一名二战飞行员。1948年他移居到纽约,开始为IBM工作,作为一位数学程序员。他四处漂流了几年,最后搬到了加利福尼亚,到IBM圣若泽研究实验室工作。Codd继续工作细化和证明的关系数据模型,一直到上世纪90年代,当他健康状况比较差时才退休。2003年4月18日,Edgar F. Codd去世,享年79岁。
在SQL Server中实现关系模型
这个阶梯不是为了教你关于关系数据建模或数据库设计,而是向你展示如何从关系模型创建SQLServer数据库。但是,在我能提供给你用于创建SQLServer数据库的代码块之前,我们首先需要探索关系数据模型。我的简单模型将包含几个实体(数据表),其中包含主键定义和不同实体之间的一些关系(外键约束)。
我的简单关系模型将是一个简单的酒店预订系统。此预订系统将要跟踪客户预订信息。图1演示了我使用T-SQL来实现的这个简单的关系模型:
图1:由6个表组成的简单关系数据库模型
通过查看这个模型,你可以看到它包含许多实体(由方框表示),以跟踪与预订相关的信息。每个实体由多个属性(列)组成,其中一个或多个属性被标识为主键(粗体和下划线名称)。总是表示的是实体之间的一些关系(用箭头表示),这些关系显示了不同实体之间关联性。我将讨论这个实体、属性、主键和关系的模型,然后,发展出一个表示这种关系模型设计的物理SQL Server数据库。
要构建一个来自于这个模型的物理数据库,我们需要识别SQLServer中的不同对象,并且根据这个模型去定义这些对象。对于图1当中的每个实体或框,我将在SQLServer中创建一个表。对于每个实体的每个属性,我将在关联表中创建一个列。对于每个主键,我将创建一个唯一的聚集索引(http://www.sqlservercentral.com/stairway/72399/)。最后,对于每个关系,我将创建一个外键约束。
开始构建我的数据库,我首先需要创建一个SQLServer数据库,以保存我计划创建的所有新数据库对象。我的数据库叫Room订票。我将使用以下T-SQL代码创建数据库:
开始从我的模型构建RoomReserve数据库对象,我将创建表对象。要在SQLServer中创建表,我需要使用CREATETABLE语句。使用CREATETABLE语句,我将能够定义每个表和每个表中的所有列。下面是创建SQLServer表的简单语法
其中:
<table_name>=表名
<Columnamedata_type,[NULL NOTNULL]
有关CREATETABLE语句的完整语法,请参阅SQLServer联机丛书。
我创建的第一个表是Customer表,它使用清单1中的代码创建。
清单1:创建Customer表
在这段代码中,当我创建Customer表时,我创建了所需要的列,但我也指定了在向该表中插入或更新记录时,该列是否需要一个值。我在某些列上指定NOT NULL,而另一些列指定NULL来实现。
如果列被定义为NOT NULL,这意味着除非用实际值填充该列,否则无法创建记录。尽管使用NULL规范定义列意味着您可以创建一行,而无需为该列指定值,或者说,另一种方法是该列允许空值。在上面的CREATETABLE语句中,我允许列Address 2和EmailAddress支持NULL,而所有其余的列都需要在创建行时提供一个值。
这个CREATETABLE语句没有完全定义我的Customer表,因为它在上面的关系数据库模型中表示。我仍然需要在列CustomerID上创建一个主键约束。此主键约束将确保本表中没有两个记录具有相同的CustomerID值。
创建主键的代码如清单2所示。
清单2:向Customer表添加主键约束此ALTERTABLE语句向我的Customer表添加了一个主键约束。
这个主键将以名为pk_Customer的聚集索引的形式创建。在Transact-SQL语言中,通常有不止一种方法来做同样的事情。或者,通过运行清单3中的CREATETABLE语句,可以一次性创建Customer表和主键。
清单3:用主键创建客户表的另一种方法
在这一点上,我已经向您展示了如何创建具有定义主键的表。唯一要展示给您的是如何创建外键约束。但在此之前,让我先向您提供创建上述关系数据库模型中其余表和主键的脚本。你可以在清单4中找到它。
清单4:创建附加表和主键约束外键约束强制两个相互关联的表之间的引用完整性。
外键约束定义的表是“引用表”,并要求在表中插入或更新行时,在另一个表中有一个相关记录,称为“Reference”表。在图1中的关系模型中,这些外键关系由箭头表示。外键约束仅在关系中的一个表上定义。在我的图表中,外键约束将定义在那些带有箭头尾(非尖头末端)的表上。要在关系模型中定义这些外键约束,我需要修改每个引用表以添加约束。清单5是我可以用来在订票表上创建外键约束的T-SQL代码。此约束确保记录不会被插入或更新到预订表中,除非在CustomerId的Customer表中找到匹配的记录。
清单5:在引用客户表的保留表上创建外键约束
为了完成我的设计,我需要在图1中的我的模型中识别出所有其他的外键合点。
清单6包含ALTERTABLE语句,以在我的数据模型中创建附加的外键约束。
清单6:创建额外的外键约束
验证数据库设计
一旦我完成了从数据模型构建数据库的工作,我应该验证实现的设计,以确保它是正确的。这个验证过程是为了确保我在物理数据库中构建的所有数据完整性规则都得到了正确的实现。在我的设计中,这里是我需要验证的规则。插入或更新的所有行必须为任何定义为NOTNULL的列定义一个特定值。作为主键的列不允许重复值。具有外键约束的列不允许在引用表中没有匹配记录的数据。在验证数据完整性规则之前,首先需要使用一些有效数据填充引用的表。我将使用清单7中的代码来填充这些表中的一些有效数据:
清单7:插入初始数据
为了验证我在数据库中构建的数据完整性规则,我将运行清单8中的INSERT语句。
清单8:使用INSERT语句测试
各种约束这些INSERT语句中的每个语句都应该失败,因为它们违反了内置到RoomReserve数据库中的数据完整性规则。第一个INSERT语句违反了ReservationStatusID列的NOTNULL验证检查。
第二个INSERT语句违反了放置在RoomType表上的主键约束。此INSERT语句试图为RoomTypeID列插入3的值。问题是RoomType表中已经有一个记录,其RoomTypeID值为3。
最后一个INSERT语句违反CustomerPaymentType表的外键约束。在这个特定的INSERT语句中,Customer表中没有值为2的CustomerID。要正确插入这些记录,需要清除插入的数据值。清理完数据后,我将能够将这些新数据插入到适当的表中。清单9包含清理后的UP INSERT语句,这些语句将通过所有数据完整性检查,并成功地插入到RoomReserve数据库中的适当表中:
清单9:附加约束测试
关系数据库设计
我的预订示例演示了如何采用关系模型并使用它实现SQLServer数据库。通过使用NOTNULL、主键和外键约束,我在数据库设计中直接构建了数据完整性规则。这允许我在底层数据库定义中强制执行这些规则,而不必在业务处理层中编写代码来验证这些数据规则。
通过这样做,我允许SQLServer数据库引擎为我执行这些数据完整性检查。通过了解和创建围绕关系数据库模型的数据库设计,您将构建一个健壮和高效的数据库实现,在这里您可以将数据完整性检查直接构建到数据库中。