到T-SQL DML 三级的阶梯:在SQL server中实现关系模型

作者: Gregory Larsen, 2017/08/02 (第一次出版: 2011/11/09) 

翻译:谢雪妮,许雅莉,赖慧芳,刘琼滨

译文:

系列

 

该文章是阶梯系列的一部分:T-SQL DML的阶梯。

 

这个阶梯将为您提供一个基本的理解,即如何使用SQL Server的翻译 SQL(T- SQL)的方言和对SQL Server表格中的数据进行处理。DML是数据操纵语言,是处理数据的语言的方面。它包括语句选择、插入、更新和删除。这个阶梯也将提供一些SQL语言的历史和一些关于集合理论的一般概念。每一层都将建立在先前的水平之上,因此当您完成时,您将很好地了解如何从SQL Server中选择和修改数据。

 

在上一级的楼梯上,我提供了关于基本选择语句和SQL历史的信息,这些级别为理解如何检索数据以及SQL环境是如何演变的提供了基础,因为技术和技术解决方案已经改变了超时工作。在这个级别,我将探索如何实现基于关系模型的简单SQL Server数据库。在开始创建数据库之前,首先让我介绍一下关系模型的创建者的一些历史。

 

关系数据建模之父

 

关系数据库设计的概念首先由Edgar F提出。. 在1970年,Codd发表论文的标题为“大型共享数据银行的数据关系模型”。 Codd在IBM工作时开发了这种建模理论。BM在Codd的数据建模概念上跳得不够快,因此并不是第一个供应关系数据库引擎的供应商,它利用了Codd的新关系数据建模理论。Codd的关系建模概念现在是用来在SQL Server和其他关系数据库引擎中创建关系数据库的框架。Codd出生于英格兰的波特兰岛,在加入皇家空军之前学习了数学和化学,成为了第二次世界大战的飞行员1948年,他搬到纽约,开始在IBM工作,在那里他是一名数学程序员。他漂流了好几年,最终搬到加州,在IBM圣何塞研究实验室工作。直到20世纪90年代,当他的健康状况不佳迫使他退休时,Codd继续努力完善并证明了关系数据模型的合理性。2003年4月18日,Codd去世,享年79岁。

 

在SQL Server中实现关系模型

 

这个阶梯不是用来教你关系数据建模,或数据库设计,而是教你如何从一个关系模型创建一个SQL Server数据库。但是在我为创建SQL Server数据库提供代码块之前,我们首先需要探索一个将被实现的关系数据模型。我的简单模型将包含一些实体(数据表),其中有主键定义和不同实体之间的一些关系(外键约束)。

 

我的简单的关系模型将是一个简单的酒店预订系统。这个预订系统需要跟踪客户预订信息。图1说明了这个简单的关系模型,我将使用t - sql实现它:

通过回顾这个模型,您可以看到它包含许多实体(由方框表示)来跟踪预订相关信息。每个实体都由一些属性(列)组成,其中一个或多个属性被标识为主键(粗体和下划线的名称)。也表示实体之间的一些关系(以箭头表示),以显示不同的实体之间是如何相互关联的。我将使用实体、属性、主键和关系的模型,然后开发一个物理SQL Server数据库,它表示此关系模型的设计。要从这个模型构建物理数据库,我们需要在SQL Server中识别基于此模型定义的不同对象。对于图1中的每个实体或框,我将在SQL Server中创建一个表。对于每个实体的每个属性,我将在关联的表中创建一个列。对于每个主键,我将创建一个唯一的集群索引(注意,使用唯一的非聚集索引也可以创建主键)。有关索引的更多信息,请参见http://www .sqlservercentral.com/stairway/72399/).。最后,对于每个关系,我将创建一个外键约束。要开始构建我的数据库,我首先需要创建一个SQL Server数据库来保存我计划创建的所有新数据库对象。我的数据库将被称为房间预订。我将使用以下的t - sql代码创建我的数据库

CREATE DATABASE RoomReservation;


要从我的模型中开始构建我的房间预订数据库对象,我将创建表对象。要在sql server中创建一个表,我需要使用创建表语句。通过创建表语句,我将能够定义每个表中的每个表和所有列。下面是创建SQL Server表的简单语法

CREATE TABLE <table_name> (
<column_definition> [,…N]);

Where:

<table_name> = Name of table
<column_definition> = column_name data_type,[NULL | NOT NULL]

For complete syntax of the CREATE TABLE statement refer to SQL Server Books Online.

The first table I create will be the Customer table, created using the code in Listing 1.

USE RoomReservation;
GO
CREATE TABLE dbo.Customer (
	CustomerId INT NOT NULL,
	FirstName NVARCHAR(50) NOT NULL, 
	LastName NVARCHAR(50) NOT NULL,
	Address1 NVARCHAR(100) NOT NULL, 
	Address2 NVARCHAR(100) NULL,
	PhoneNumber NVARCHAR(22) NOT NULL, 
	EmailAddress VARCHAR(100) NULL, 
	City VARCHAR(100) NOT NULL,
	StateProvince NVARCHAR(100) NOT NULL,
	PostalCode NVARCHAR(100) NOT NULL);

 

清单1:创建Customer表

在这段代码中,当我创建我的Customer表时,我创建了我需要的所有列,但我还指定了在插入或更新记录时,该列是否需要一个值。我通过在某些列上指定非空值来实现这一点,而其他列则指定为空值。

如果一个列被定义为不为空,那意味着你不能创建一个记录,除非你用一个实际值填充这个列。而使用空值规范定义一个列意味着您可以创建一行,而不必为这个列指定一个值,或者另一种方法是,该列允许空值。我在创建表的语句上面我允许列地址2和邮箱地址支持空值,而所有其他的柱子需要值将提供创建一个行时。

这个创建表语句并没有完全定义我的客户表,因为它是在我上面的关系数据库模型中表示的。我还需要创建一个主键约束的列ID。这个主键约束将确保该表中没有两个记录具有相同的客户编号码的值。这个主键约束将确保该表中没有两个记录具有相同的客户编号码的值。创建主键的代码如清单2所示

USE RoomReservation;
GO
CREATE TABLE dbo.Customer (
	CustomerId INT NOT NULL CONSTRAINT PK_Customer PRIMARY KEY,
	FirstName NVARCHAR(50) NOT NULL, 
	LastName NVARCHAR(50) NOT NULL,
	Address1 NVARCHAR(100) NOT NULL, 
	Address2 NVARCHAR(100) NULL,
	PhoneNumber NVARCHAR(22) NOT NULL, 
	EmailAddress NVARCHAR(100) NULL, 
	City VARCHAR(100) NOT NULL,
	StateProvince NVARCHAR(100) NOT NULL,
	PostalCode NVARCHAR(100) NOT NULL);

清单2:向客户表添加主键约束
此表语句向客户表添加了主键约束。该主键将在聚集索引命名pk_customer窗体的创建。在翻译SQL语言中,通常有不止一种方法来做同样的事情。另外,我可以通过运行清单3中的创建表语句一次性创建我的客户表和主键。

 

USE RoomReservation;
GO
CREATE TABLE dbo.Customer (
	CustomerId INT NOT NULL CONSTRAINT PK_Customer PRIMARY KEY,
	FirstName NVARCHAR(50) NOT NULL, 
	LastName NVARCHAR(50) NOT NULL,
	Address1 NVARCHAR(100) NOT NULL, 
	Address2 NVARCHAR(100) NULL,
	PhoneNumber NVARCHAR(22) NOT NULL, 
	EmailAddress NVARCHAR(100) NULL, 
	City VARCHAR(100) NOT NULL,
	StateProvince NVARCHAR(100) NOT NULL,
	PostalCode NVARCHAR(100) NOT NULL);
清单3:用主键创建客户表的另一种方法
在这一点上,我已经向您展示了如何创建具有定义主键的表。唯一要展示给您的是如何创建外键约束。但在此之前,让我先向您提供创建上述关系数据库模型中其余表和主键的脚本。您可以在清单4中找到它。
USE RoomReservation;
GO

CREATE TABLE dbo.Reservation (
	ReservationId INT NOT NULL, 
	ArrivalDate DATETIME NOT NULL,
	DepartureDate DATETIME NOT NULL,
	DailyRate SMALLMONEY NOT NULL,
	ReservationStatusID INT NOT NULL,
	CustomerId INT NOT NULL, 
	RoomTypeID INT NOT NULL);
	
ALTER TABLE dbo.Reservation ADD CONSTRAINT
    PK_Reservation PRIMARY KEY CLUSTERED (ReservationId);
	
CREATE TABLE dbo.RoomType (
	RoomTypeId INT NOT NULL,
	RoomDesc NVARCHAR(1000) NOT NULL); 
	
ALTER TABLE dbo.RoomType ADD CONSTRAINT
    PK_RoomType PRIMARY KEY CLUSTERED (RoomTypeId);

CREATE TABLE dbo.ReservationStatus (
	ReservationStatusId INT NOT NULL, 
	ReservationStatusDesc NVARCHAR(50) NOT NULL);

ALTER TABLE dbo.ReservationStatus ADD CONSTRAINT
    PK_ReservationStatus PRIMARY KEY CLUSTERED (ReservationStatusId);
	
CREATE TABLE dbo.PaymentType (
	PaymentTypeId INT NOT NULL, 
	PaymentTypeDesc NVARCHAR(50) NOT NULL); 

ALTER TABLE dbo.PaymentType ADD CONSTRAINT
    PK_PaymentType PRIMARY KEY CLUSTERED (PaymentTypeId);

CREATE TABLE dbo.CustomerPaymentType (
	PaymentTypeId INT NOT NULL, 
	CustomerId INT NOT NULL, 
	PaymentNotes NVARCHAR(2000) NULL);

ALTER TABLE dbo.CustomerPaymentType ADD CONSTRAINT
    PK_CustomerPaymentType PRIMARY KEY CLUSTERED (PaymentTypeId, CustomerId);

清单4:创建额外的表和主键约束

一个外键约束在两个相互关联的表之间强制引用完整性。外键约束定义的表是“引用表”,需要在另一个表中有相关的记录,称为“引用”表,任何时候在表中插入或更新一行。在图1的关系模型中,这些外键关系由箭头表示。外键约束只在关系中的一个表上定义。在我的图表中,外键约束将定义在具有箭头尾部(无尖端)的那些表上。

为了在关系模型中定义这些外键约束,我需要修改每个引用表来添加约束。清单5是我可以用来在保留表上创建外键约束的t - sql代码。这个约束确保记录不会被插入或更新到预订表中,除非在顾客表中基于客户编号找到匹配的记录。

 

USE RoomReservation;
GO
ALTER TABLE dbo.Reservation
ADD CONSTRAINT FK_Reservation_CustomerPaymentType FOREIGN KEY (CustomerId)
    REFERENCES dbo.Customer (CustomerID);


清单5:在引用客户表的预订表上创建一个外键约束
为了完成我的设计,我需要实现其他所有外键约束的图1在我的模型识别。清单6包含了在我的数据模型中创建额外外键约束的变更表语句。

USE RoomReservation;
GO
ALTER TABLE dbo.Reservation
ADD CONSTRAINT FK_Reservation_CustomerPaymentType FOREIGN KEY (CustomerId)
    REFERENCES dbo.Customer (CustomerID);
清单6:创建额外的外键限制

验证数据库的设计

  一旦我完成了从数据模型构建数据库的工作,我应该验证所实现的设计,以确保它是正确的。这个验证过程是确保我在物理数据库中构建的所有数据完整性规则都正确地实现了。在我的设计中,我需要验证这些规则。

    所有插入或更新的行必须对定义为非空值的列有一个特定的值。

主键的列不允许重复的值。

具有外键约束因素的列不允许在引用表中没有匹配记录的数据。

验证数据完整性规则之前,我首先需要用一些有效数据填充引用的表。我将使用清单7中的代码来填充那些有一些有效数据的表:

 

SET NOCOUNT ON;
-- Create PaymentType records
INSERT INTO PaymentType VALUES(1,'Visa');
INSERT INTO PaymentType VALUES(2,'MasterCard');
INSERT INTO PaymentType VALUES(3,'American Express');
-- Create Customer 
INSERT INTO Customer VALUES 
    (1,'Greg','Larsen','123 Some Place'
      ,NULL,'123-456-7890',Null,'MyCity','MA','12345');
-- Create Reservation Status
INSERT INTO ReservationStatus VALUES (1,'Booked');
INSERT INTO ReservationStatus VALUES (2,'Cancelled');
-- Create Room Type
INSERT INTO RoomType VALUES (1,'Kingsize');
INSERT INTO RoomType VALUES (2,'Queen');
INSERT INTO RoomType VALUES
清单7:插入初始数据

为了验证我在数据库中构建的数据完整性规则,我将运行清单8中的INSERT语句。

USE RoomReservation;
GO
-- Violates NOT NULL constraint
INSERT INTO Reservation VALUES(1,'2011-8-1 5:00 PM'
                                ,'2011-8-2 9:00 AM' 
                                , 150.99,1,1,1);                                                                                                                                                          
-- Violates Primary Key Constraint
INSERT INTO RoomType VALUES (4,'Suite');  
-- Violates Foreign Key Constraint
INSERT INTO CustomerPaymentType VALUES (1,1,'Will need an internet connection');
清单8:用INSERT语句测试各种约束

这些INSERT语句中的每一个都应该失败,因为它们违反了构建在订房数据库中的数据完整性规则。第一个INSERT语句违反了预订规则列的非空验证检查。

第二个INSERT语句违反了放在房间类型表上的主键约束。这个INSERT语句试图为房间类型编号的列插入3的值。问题是在房间类型值为3的房间类型表中已经有了记录。

最后一个INSERT语句违反了顾客缴费方式表的外键约束。在这个特殊的INSERT语句中,顾客表中没有客户编号值为2的值。

要正确地插入这些记录,插入的数据值需要清理。一旦数据被清理干净,我就可以将这些新数据插入到合适的表中。清单9包含清除所有数据完整性检查并成功插入到房间预订数据库中的适当表的清理INSERT语句:

USE RoomReservation;
GO
-- Violates NOT NULL constraint
INSERT INTO Reservation VALUES(1,'2011-8-1 5:00 PM'
                                ,'2011-8-2 9:00 AM' 
                                , 150.99,1,1,1);                                                                                                                                                          
-- Violates Primary Key Constraint
INSERT INTO RoomType VALUES (4,'Suite');  
-- Violates Foreign Key Constraint
INSERT INTO CustomerPaymentType 


清单9:附加约束测试
 

关系数据库设计

我的预订示例演示了如何使用关系模型并使用它来实现SQL Server数据库。通过使用非空值、主键和外键完整性约束,我将数据完整性规则构建到数据库设计中。这允许我在底层数据库定义中执行这些规则,而不必在业务处理层中编写代码来验证这些数据规则。通过这样做,我允许SQL Server数据库引擎为我执行这些数据完整性检查。

通过了解并在关系数据库模型周围创建数据库设计,您将构建一个健壮且高效的数据库实现,您可以在数据库中构建数据完整性检查。

posted @ 2017-10-18 01:13  哗啦啦啦啦  阅读(711)  评论(0编辑  收藏  举报