职业能力目标和学习要求
在企业信息化系统中,数据库具有十分重要的地位,它是系统正常运行的基础,因此数据库设计是应用程序设计中最为关键的一项任务。MySQL是目前非常流行的、开源的、小型关系型数据库管理系统,在许多Web类型的项目开发中有着广泛的应用。通过本模块的学习,可以培养以下职业能力并完成相应的学习要求。
职业能力目标:
- 能进行MySQL数据库的设计与管理。
- 培养项目思路,提高动手操作能力。
- 促进学生形成工程化的思维习惯:自顶向下、逐步精化。
学习要求:
- 解数据建模与设计。
- 掌握MySQL数据库的管理。
- 了解MySQL数据库编程。
项目导入
2.1 诚信管理论坛数据库设计
数据库设计的主要目的是将现实世界中的事物及联系用数据模型描述,是应用程序设计中最为关键的一项任务。本节将介绍以下主要内容。
- 数据库建模技术。
- 数据库概念模型设计。
- 数据库物理模型设计。
任务
请根据诚信管理论坛的需求,完成以下任务。
(1)设计诚信管理论坛的概念模型。
(2)设计诚信管理论坛的物理模型。
2.1.1 数据库建模技术
相关知识
在企业信息化系统中,数据库具有十分重要的地位,它是系统正常运行的重要基础,因此数据库设计是应用程序设计中最为关键的一项任务。一个良好的数据库设计可以:
- 节省数据的存储空间;
- 保证数据的完整性;
- 方便进行数据库应用系统的开发。 数据库设计的主要目的是为了将现实世界中的事物及联系用数据模型(Data Model,DM)描述,即信息数据化。数据模型就是现实世界的模拟,通常数据模型分成两大类:一类是按用户的观点来对数据和信息建模,称为概念模型或信息模型;另一类是按计算机系统的观点对数据建模,主要包括网状模型、层次模型、关系模型等,数据建模的主要目的是将用户的需求从现实世界转换到数据库世界,其具体模型如图2.1.1所示。
一个软件项目开发周期通常可分为需求分析、概要设计、详细设计、代码编写、软件测试和安装部署6个阶段,其中,需求分析阶段主要是分析客户的业务和数据处理需求;概要设计阶则需要设计数据库的E-R模型图,确认需求信息的正确性和完整性;然后在详细设计阶段将E-R图转换为表,进行逻辑设计,并应用数据库设计的三大范式进行审核;最后在代码编写阶段选择具体数据库进行物理实现,并编写代码。
因此,诚信管理论坛的开发也将按照以上步骤进行,在需求分析阶段与本书系统有关人员进行交流、座谈,充分理解系统需要完成的任务,诚信管理论坛的基本需求具体见1.1节。
2.1.2 数据库概念模型设计
相关知识
概念模型设计是概要设计阶段的主要任务,通常是设计数据库的实体-关系(E-R)模型图,确认需求信息的正确性和完整性。E-R模型是由Peter Chen在1976年引入的,它使用实体(Entity)和关系(Relation)来模拟现实世界,为了便于描述,现给出关系模型中的几个重要术语的定义。
客观存在并可以区分的事物称为实体(Entity)。
实体所具有的某一特性称为属性(Attribute)。
能唯一标识实体的属性的集合称为码(Key)。
实体集合间存在的相互联系称为关系(Relation)。
E-R图可以将数据库的全局逻辑结构图形化表示,它是从计算机角度出发来对数据进行建模,其设计步骤如下。
1.确定所有实体集合
用矩形方框表示实体集合,方框内标明实体集合名称。
2.选择实体集应包含的属性
用椭圆框表示属性,通过无向边连接到实体集。只有一个属性的实体集可用属性代替,附加到它参加的关系上。
3.确定实体集之间的关系
用菱形框表示关系,框内标明关系的名称,通过无向边(或有向边)连接到参加关系的每个实体集合。
4.确定实体集的主键
用下画线在属性上标明主键的属性集合。
5.确定关系的类型
在用无向边连接关系到实体集时,在边上注明1或n(多)来说明关系的类型。E-R图中常用的符号如图2.1.2所示。
示例2.1.1 绘制诚信管理论坛的E-R图
绘制系统的E-R图,通常要先建立系统的概念模型,可以分为以下5步。
(1)确定实体集合。
要确定诚信管理论坛的实体集合,即标识数据库要管理的全部关键对象或实体,此类实体通常是名词,根据诚信管理论坛的需求,不难发现在系统中有以下关键实体。
用户(User):论坛的使用者,即普通用户。
帖子(Topic):用户发的主帖;
回帖(Reply):用户发的跟帖(回帖)。
版块(Board):论坛的各个版块信息。
通过以上分析,得出系统的实体集后,需要在PowerDesign中建立对应的概念模型,其操作步骤如下。
① 启动PowerDesign,新建概念模型。选择“File”→“New”,弹出“New”对话框,在模型类型(Model type)中选择“概念模型(Conceptual Data Model)”,在右方General选项卡中的模型名称(Model name)中输入“CXBBS”,如图2.1.3所示。单击“确定”按钮后,创建一个空白的概念模型。
② 创建实体。单击Palette面板中的“Entity”工具 ,在模型区域单击鼠标左键,在鼠标单击的位置出现Entity的图符,默认的命名方式为Entity_n,其中n为当前实体在创建中的次序,如图2.1.4所示。其中,第一栏Entity_n为实体名,实体的属性建立后将放在第二栏,实体中若定义了标识符,则在第三栏显示。
将Entity_1的名称改为“用户”,并依次创建帖子、回帖和版块实体,创建好的实体如图2.1.5所示。
(2)确定实体应包含的属性。
确定实体所包含的属性是概念模型设计中的难点,要综合考虑系统的功能要求和现实情况,属性通常情况下是名词,诚信管理论坛中各实体的属性如下。
用户:需要记录用户的姓名(name)、登录密码(password)、性别(Gender)、注册时间(RegTime),并可根据爱好设定头像(head),同时还要增加用户编号(ID)。
帖子:需要记录帖子的标题(Title)、内容(Content)、发表时间(publishTime)、修改时间(modifyTime),同时还要增加帖子编号(ID)。
回帖:需要记录回帖的标题(Title)、内容(Content)、回帖时间(publishTime)、回帖的修改时间(modifyTime),同时还要增加回帖编号(ID)。
版块:需要记录版块的名称(Name)、编号(ID),以及上级版块编号(ParentID)。
通过以上分析,得出系统实体集的属性后,需要在PowerDesign中添加相关属性,其操作步骤如下。
① 添加用户实体的属性。单击鼠标右键或单击Palette面板中的 工具,返回选择状态。双击“用户”实体,或用鼠标右击该图符,在弹出的快捷菜单中选择“Properties”命令,弹出实体的属性窗口,选择Attributes属性页,为该实体添加相关属性。这里,为用户添加了用户编号、用户名、密码、性别、注册时间、头像6个属性,如图2.1.6所示。
② 添加属性的数据类型。在设置实体属性时,通常需要指明属性的数据类型,在DataType中对每个属性的数据类型进行设置,如Variable characters (50)表示变长字符串,长度为50,Date & Time表示日期时间类型。图2.1.6中各属性的“M”表示强制(Mandatory),即该属性不能为空;“P”表示主标识符(Primary Identifier);“D”表示在图形模型中显示该属性。设置数据类型后的用户实体如图2.1.7所示。
③ 添加各实体属性。按照同样的操作方式,分别新增帖子、回帖和版块的各自属性,完成后的概念模型如图2.1.8所示。
(3)确定实体之间的关系。
关系通常是动词,根据系统的功能分析,可知诚信管理论坛存在以下关系。
用户与帖子之间存在“发帖”关系。
用户与回帖之间存在“回帖”关系。
帖子与回帖之间存在“回复”关系。
版块与帖子之间存在“拥有”关系。
通过以上分析,得出系统实体集的属性后,需要在PowerDesign中添加相关属性,其操作步骤如下。
① 建立版块与帖子的拥有关系。单击Palette面板中的“Relationship”工具 ,在实体版块上按住鼠标左键不放,拖动鼠标到目标实体帖子,松开鼠标,这样就在两个实体之间建立了关系。
单击鼠标右键或单击Palette面板中的 工具,使鼠标返回选择状态。
双击关系(Relationship)的连线,或者用鼠标右键单击该图形,在弹出的快捷菜单中选择“Properties”命令,弹出Relationship Properties窗口,在General属性页修改Relationship的Name为“拥有”,单击“确定”按钮。如图2.1.9所示。
② 添加各实体之间的关系。按照同样的操作方式,分别新增帖子、回帖和用户之间的关系,完成后的概念模型如图2.1.10所示。
(4)确定实体集的主键。
主键(Primary Key)是实体中的一个或多个属性,它的值用于唯一标识一个实体对象,在本系统中由于各实体都有编号属性用于标识,因此只需将编号设为各自实体的主键即可。在PowerDesign中添加实体主键的步骤如下。
① 添加“用户”实体的主键。用鼠标右键单击“用户”,在弹出的快捷菜单中选择“Properties”命令,弹出实体的属性窗口,选择“Attributes”属性页,选中“编号”属性,单击 按钮,弹出“Identifer Properties”(标识符属性)窗口,在其中的Name栏中输入“PK_USER”,同时选中下方的“Primary identifer”(主标识符),如图2.1.11所示。单击“确定”按钮,即可创建用户实体的主键。
可以单击“identifiers”属性页,查看实体所拥有的键。
② 添加各实体的主键。按照①的操作步骤依次添加“帖子”、“回帖”和“版块”实体的主键,完成的概念模型如图2.1.12所示。
(5)确定关系的类型。
根据一个实体可以和多少个另一类实体集合的实体相联系,可将关系分为一对一、一对多、多对一和多对多4种类型,根据诚信管理论坛的实际需求,各类关系的类型分别如下。
用户与帖子的“发帖”关系属于一对多关系。
用户与回帖的“回帖”关系属于一对多关系。
帖子与回帖的“回复”关系属于一对多关系。
版块与帖子的“拥有”关系属于一对多关系。
在PowerDesign中设置关系类型的操作步骤如下。
① 设置“拥有”关系的类型。双击“拥有”关系,弹出关系的属性窗口,选择“Cardinality”属性页,如图2.1.13所示。
其中,关系类型可以是One-One(一对一)、One-Many(一对多)、Many-One(多对一)和Many-Many(多对多)。下方的“版块to帖子”和“帖子to版块”分别显示了版块和帖子的映射关系。
② 设置各关系属性。分别确定各关系的属性,由于本例中各关系均为一对多关系,所以最终的概念模型如图2.1.12所示。
练一练
1.熟悉PowerDesigner环境。
2.某图书馆借阅管理数据库要求提供以下服务。
(1)可随时查询书库中现有书籍的品种、数量与存放位置,所有书籍均可由书号唯一标识。
(2)可随时查询书籍借还情况,包括借书人单位、姓名、借书证号、借书日期和还书日期。 规定:任何人可借多种书,任何一种书可为多个人所借,借书证号具有惟一性。
(3)当需要时,可通过数据库中保存的出版社的电报编号、电话、邮编及地址等信息向相应出版社增购有关书籍。注意:一个出版社可出版多种书籍,同一本书仅为一个出版社出版,出版社名具有唯一性。
请根据以上描述,建立图书管理系统的概念模型。
2.1.3 数据库物理模型设计
相关知识
虽然E-R图有助于人们理解数据库中的实体和关系,但是,在进行具体软件系统开发时,还需要将信息世界的E-R图转换为计算机中的数据集合,目前使用最多的是关系数据库模型。由于两种模型都是现实世界抽象的逻辑表示,采用类似的设计原则,因此可以将E-R设计转换为关系设计,即将E-R模式转化为表。虽然关系和表之间存在区别,但在不太严格的情况下,可以将关系看成是某些值形成的一个表。可以将符合E-R数据库模式的数据库表示为一些表的集合。数据库的每个实体集和关系集都有唯一的表与之对应,表名即为相应的实体集或关系集的名称。每个表有多个列,每列有唯一的列名。数据库物理模型设计的具体步骤如下。
(1)将各实体转换为对应的表,将各属性转换为各表对应的列。
(2)标识每个表的主键列,需要注意的是:没有主键的表建议添加ID编号列作为主键或外键。
(3)在表之间建立主外键,体现实体之间的映射关系。
任务解决
示例2.1.2 完成诚信管理论坛系统的物理模型,通常可以分为以下3步:
(1)将实体转化为表;
(2)标识表中的主键;
(3)建立表的主外键。
本例将演示如何使用PowerDesign建立系统的物理模型。
一般情况下,可以给E-R图中的每一个实体建立一张表,表名就是实体名,表的属性就是实体的属性。在PowerDesign中建立对应的物理模型,可以采用逐个实体转换的方式,其操作方式类似于创建概念模型,但在已经拥有概念模型的情况下,PowerDesign提供了一种自己生成物理模型的方式,其操作步骤如下。
① 选择“Tools”(工具)菜单下的“Generate Physical Data Model …”(生成物理模型),弹出“PDM Generation Options”(PDM生成选项)窗口,在“General”选项卡中,选择需要生成的物理模型所对应的DBMS,本例中采用MySQL 5.0做为数据库管理系统,其余采用默认选项即可,如图2.1.14所示,单击“确定”按钮,即可生成新的物理模型。
② 修改列名和关系名。由于在自动转换时,PowerDesign会自动将实体转换成表,为转换成物理模型后便于编码,因此需要将采用中文名的实体名称和代码改为英文,其具体映射关系如表2.1.1~表2.1.5所示。
完成后的物理模型如图2.1.15所示。
③ 更新概念模型。使用Powerdesign工具可以非常方便地维护系统的概念模型和物理模型,在对物理模型进行修改后,可以选择“Tools”(工具)菜单下的“Generate Conceptual Data Model”(生成概念模型),弹出“CDM Generation Options”(CDM生成选项)窗口,在“General”选项卡中,会自动选择“update existing Conceptual Data Model”(更新已有概念模型),单击“确定”按钮,即可更新对应的概念模型,如图2.1.16所示。
④ 生成数据库。使用PowerDesign还可以非常方便地生成最终数据库的创建脚本,通常选择菜单“DataBase”下的“Generate Database”命令,即可完成相关任务。由于本书还将逐步介绍MySQL下的各类DDL和DML语句,这里就不再详述,读者可自行尝试。
练一练
使用PowerDesign完成图书馆借阅系统数据库的物理模型。
2.2 诚信管理论坛数据库实现
数据库是存储数据对象的容器,包括表、约束、视图、触发器、存储过程等。其中,表是最基本的数据对象,用于存放数据。约束是保持数据库完整性的一种方法,定义了可输入表或表的单个字段中的数据限制条件。本节将介绍以下主要内容。
- 创建项目数据库。
- 创建项目数据表。
- 创建数据约束。
任务
请根据诚信管理论坛的物理模型,完成以下任务。
(1)创建诚信管理论坛的数据库。
(2)创建诚信管理论坛的数据表。
(3)创建诚信管理论坛的数据表约束。
2.2.1 创建项目数据库
相关知识
数据库是存储数据对象的容器,对数据库的操作如下。
- 查看数据库:显示系统中的全部数据库。
- 创建数据库:创建一个新的数据库。
- 切换数据库:切换默认数据库。
- 修改数据库:修改数据库的参数。
- 删除数据库:删除一个数据库。
1.查看数据库
使用SHOW DATABASES命令可查看系统中的数据库列表,其语法格式如下。
2.创建数据库
使用CREATE DATABASE或CREATE SHEMA命令可以创建数据库,其语法格式如下。
说明:
语句中“[ ]”内为可选项。
- db_name:数据库名。MySQL的数据库在文件系统中是以目录方式表示的,因此,命令中的数据库名称必须符合操作系统文件夹命名规则。同时要注意的是,在MySQL中数据库名是不区分大小写的。
- IF NOT EXISTS:在创建数据库前进行判断,只有该数据库目前尚不存在时才执行。
- CREATE DATABASE操作。用此选项可以避免出现数据库已经存在而再新建的错误。
- DEFAULT:指定默认值。
- CHARACTER SET:指定数据库字符集(Charset),charset_name为字符集名称。
- COLLATE:指定字符集的校对规则,collation_name为校对规则名称。
3.使用数据库
在MySQL中可以同时存在多个数据库,因此需要使用USE命令来指定默认数据库,其语法格式如下。
USE db_name;
为了能够确认当前的默认数据库,MySQL中提供了以下命令,用于查看默认数据库。
SELECT DATABASE();
4.修改数据库
数据库创建后,如果需要修改数据库的参数,可以使用ALTER DATABASE命令,其语法格式如下。
其中alter_specification:
说明:
ALTER DATABASE用于更改数据库的全局参数,这些参数保存在数据库目录中的db.opt文件中。用户只有具有修改数据库的权限,才可以使用ALTER DATABASE。修改数据库的选项与创建数据库相同,不再重复说明。如果语句中忽略数据库名称,则修改当前(默认)数据库的参数。
5.删除数据库
已经创建的数据库需要删除时,可以使用DROP DATABASE命令,其语法格式如下。
DROP DATABASE [IF EXISTS] db_name
说明:
db_name是要删除的数据库的名称。可以使用IF EXISTS子句可以避免删除不存在的数据库时出现MySQL错误信息。
注意:这个命令必须小心使用,因为它将删除指定的整个数据库,该数据库的所有表(包括其中的数据)也将永久删除。
练一练
1.列出当前系统中的全部数据库。
2.创建诚信管理论坛系统数据库CXBBS。
3.使用诚信管理论坛系统数据库CXBBS。
4.修改诚信管理论坛系统数据库CXBBS的默认字符集和校对规则。
任务解决
示例2.2.1 显示当前系统中的全部数据库。
(1)打开MySQL控制台。在屏幕下方的任务栏区域,单击WAMPSERVER图标 ,在弹出的菜单中,选择“MySQL”菜单下的“MySQL控制台(m)”,打开MySQL控制台,如图2.2.1所示。
(2)输入MySQL用户密码。在输入密码提示行中输入MySQL用户密码,连接到MySQL数据库,如图2.2.2所示。
(3)查看数据库列表。在命令行提示符处,输入“SHOW DATABASES;”命令,查看系统中的数据库列表,如图2.2.3所示。
注意:show databases命令中database后面要加“s”,每条命令需以“;”结束。
在MySQL中有3个系统默认数据库,分别是mysql、informationshcema和performance
shema。
(4)筛选数据。SHOW DATABASES命令可以后接LIKE或WHERE子句,从而实现对数据的过滤。例如,只显示含有“m”的数据库名称,可以使用以下命令。
SHOW DATABASES LIKE '%m%';
也可以使用以下命令。
SHOW DATABASES WHERE 'Database' like '%m%';
示例2.2.2 创建诚信管理论坛系统数据库CXBBS。
在MySQL控制台窗口中,输入“CREATE DATABASE CXBBS”,其结果如图2.2.4所示。
示例2.2.3 使用诚信管理论坛系统数据库CXBBS。
(1)在MySQL控制台窗口中,输入“SELECT DATABASE();”,查看默认数据库,其结果如图2.2.5所示。
(2)在MySQL控制台窗口中,输入“USE CXBBS;”,将CXBBS设为默认数据库,其结果如图2.2.6所示。
示例2.2.4 修改诚信管理论坛系统数据库CXBBS的默认字符集和校对规则。
在MySQL控制台窗口中,输入以下命令,将CXBBS数据库的默认字符集设为utf8,校对规则设为utf8_general_ci,其结果如图2.2.7所示。
ALTER DATABASE cxbbs
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
2.2.2 创建项目数据表
相关知识
数据表是数据库存放数据的数据对象,是存储数据对象的容器,没有表,数据库中其他的数据对象就没有意义。对数据表的操作包括以下几种。
- 查看数据表:显示默认数据库中的全部数据表。
- 创建数据表:创建一个新的数据表。
- 修改数据表:更改数据表的结构。
- 重命名数据表:修改数据表的名称。
- 删除数据表:删除一个数据表及其全部数据。
1.查看数据表
使用SHOW TABLES命令可显示数据库中的数据表列表,其语法格式如下。
使用该命令可查看数据库中的数据表列表,通过使用FORM或IN参数可以指定查看的数据库名称,通过LIKE或WHERE参数可以指定显示的过滤条件。
如果需要查看一个数据表的具体信息,则可以使用DESCRIBE命令,其语法格式如下。
{DESCRIBE | DESC} tbl_name [col_name | wild]
通常会使用该命令的缩写形式DESC,如DESC tbl_user。
2.创建数据表
数据表是十分重要的数据对象,用户所关心的数据分门别类地存储在各个表中,许多操作都是围绕表进行的。因此,表的好坏将直接影响数据库系统的执行效率。因此,在创建表之前,一定要做好系统分析,以免表创建以后再修改,这样有时会很麻烦。在建表之前,首先需要知道每个属性的数据类型,MySQL数据类型有以下几种。
(1)数值型。
DECIMAL和NUMERIC(M,D):定义数据类型为数值型,其最大长度为M位,小数位为D位,常用于“价格”、“金额”等对精度要求不高但准确度要求非常高的字段。
FLOAT(p):定义数据类型为浮点数值型,其精度等于或大于给定的精度p。
DOUBLE:定义数据类型为双精度浮点类型,它的精度由执行机构确定。
BIT[(M)]:位字段类型。M表示每个值的位数,范围为1~64。如果省略M,则默认为1。
TINYINT[(M)] [UNSIGNED] [ZEROFILL]:表示很小的整数。带符号的范围是-128~127。无符号的范围是0~255,[UNSIGNED]表示无符号,[ZEROFILL]表示不足最大位数的需补0。
BOOL、BOOLEAN:表示布尔类型,其范围与TINYINT(1)相同。0值被视为假。非0值视为真。
SMALLINT[(M)] [UNSIGNED] [ZEROFILL]:表示小整数。带符号的范围是-32768~32767。无符号的范围是0~65535。
MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]:表示中等大小的整数。带符号的范围是-8388608~8388607。无符号的范围是0~16777215。
INT和INTEGER[(M)] [UNSIGNED] [ZEROFILL]:表示普通大小的整数。带符号的范围是-2147483648~2147483647。无符号的范围是0~4294967295。
BIGINT [(M)] [UNSIGNED] [ZEROFILL]:表示大整数。带符号的范围是-9223372036854775808~9223372036854775807。无符号的范围是0~18446744073709551615。
注意:TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT占用的存储空间分别为1字节、2字节、3字节、4字节和8字节。
(2)日期时间型。
DATE:表示日期型数据,支持的范围为'1000-01-01'~'9999-12-31',在MySQL中以'YYYY-MM-DD'格式显示DATE值。
DATETIME:表示日期时间型数据,支持的范围是'1000-01-01 00:00:00'~'9999-12-31 23:59:59',在MySQL中以'YYYY-MM-DD HH:MM:SS'格式显示DATETIME值。
TIMESTAMP[(M)]:表示时间戳,其范围是'1970-01-01 00:00:00'~2037年,在MySQL中,'以YYYY-MM-DD HH:MM:SS'格式的字符串显示TIMESTAMP值,其宽度固定为19个字符。
TIME:表示时间类型。范围是'-838:59:59'~'838:59:59'。在MySQL中以'HH:MM:SS'格式显示TIME值。
YEAR[(2|4)]:表示年份数据,其格式为2位或4位,默认是4位格式。在4位格式中,允许的值是1901~2155和0000。在2位格式中,允许的值是70~69,表示从1970年~2069年。在MySQL中以YYYY格式显示YEAR值。
(3)字符串型。
CHAR(M) [BINARY| ASCII | UNICODE]:表示固定长度字符串,当保存时在右侧填充空格以达到指定的长度。M表示列长度。M的范围是0到255个字符,BINARY属性是指定列字符集的二元校对规则;可以为CHAR指定ASCII属性,表示该字段使用latin1字符集;也可以为CHAR指定UNICODE属性,表示该字段使用ucs2字符集。
VARCHAR(M) [BINARY]:表示变长字符串。M表示最大列长度。M的范围是0到65,535,变长字符串是使用最多的数据类型之一。
BINARY(M):表示固定二进制字节字符串,与CHAR类型类似。
VARBINARY(M):表示可变长二进制字节字符串,与VARCHAR类型类似。
BLOB[(M)]:表示最大长度为65535(216–1)个字节的BLOB列,M表示可容纳的最小字节数。
TEXT[(M)]:表示最大长度为65535(216–1)个字符的TEXT列。
MEDIUMBLOB:表示最大长度为16777215(224–1)个字节的BLOB列。
MEDIUMTEXT:表示最大长度为16777215(224–1)个字符的TEXT列。
LONGBLOB:表示最大长度为4294967295或4GB(232–1)个字节的BLOB列。
LONGTEXT:表示最大长度为4294967295或4GB(232–1)个字符的TEXT列。
ENUM('value1','value2',...):表示枚举类型,使用枚举类型的字段,其值只能为'value1','value2',...,NULL中或'',一个枚举最多可定义65535个值,在内部用整数表示,从0开始。
SET('value1','value2',...):表示集合类型。使用集合对象的字段,其值可以是集合中的0个或多个值,但其值必须来自'value1','value2',...中。一个集合列最多可定义64个值,在内部用整数表示。
为便于查询,列出MySQL中的数据类型如表2.2.1所示。
在MySQL中创建表的基本语法格式如下。
说明:
- TEMPORARY:该关键字表示用CREATE命令新建的表为临时表。不加该关键字创建的表通常称为持久表,在数据库中持久表一旦创建就会一直存在,多个用户或者多个应用程序可以同时使用持久表。临时表只对创建它的用户可见,当断开与该数据库的连接时,MySQL会自动删除。
- IF NOT EXISTS:在建表前加上一个判断,只有该表目前尚不存在时才执行CREATE TABLE操作,使用该选项可以避免出现表已经存在而无法再新建的错误。
- table_name:要创建的表名。该表名必须符合标识符的命名规则,如果有MySQL保留字必须用单引号括起来。
- column_definition:列定义,包括列名、数据类型,可能还有一个空值声明和一个完整性约束。
- index_definition:表索引项定义,主要定义表的索引、主键、外键等,具体定义将在后续讨论。
- table_option:用于描述表的选项。
- select_statement:可以在CREATE TABLE语句的末尾添加一个SELECT语句,在现有表的基础上创建表。
3.修改数据表
ALTER TABLE用于更改原有表的结构。例如,可以增加或删减列、创建或取消索引、更改原有列的类型、重新命名列或表,还可以更改表的评注和表的类型。语法格式如下。
说明:
- tb1_name:表名。
- col_name:指定的列名。
- IGNORE:是MySQL相对于标准SQL的扩展。如果在修改后的新表中存在重复关键字而且没有指定IGNORE,会操作失败。如果指定了IGNORE,则对于有重复关键字的行只使用第一行,其他有冲突的行被删除。
- column_definition:定义列的数据类型和属性,具体内容在CREATE TABLE的语法中已做说明。
- ADD[COLUMN]子句:向表中增加新列。例如,在表tbl_user中增加列mail_addr。
ALTER TABLE tbl_user ADD COLUMN mail_addr varchar(100);
- FIRST | AFTER col_name:表示在某列的前或后添加,不指定则添加到最后。
- ALTER [COLUMN]子句:修改表中指定列的默认值。
- CHANGE [COLUMN]子句:修改列的名称。重命名时,需给定旧的和新的列名和列当前的类型,old_col_name表示旧的列名。在column_definition中定义新的列名和当前数据类型。例如,将email列的名称变更为mail_addr。
ALTER TABLE tbl_user CHANGE COLUMN mail_addr email varchar(100);
- MODIFY [COLUMN]子句:修改指定列的数据类型。例如,将email列的数据类型改为varchar(160):
ALTER TABLE tbl_user MODIFY email varchar(160);
- DROP子句:从表中删除列或约束,如删除email列。
ALTER TABLE tbl_user DROP email;
- RENAME子句:修改该表的名称,new_tbl_name是新表名,如将tbl_user改为user。
ALTER TABLE tbl_user RENAME TO user;
- ORDER BY子句:使表中的数据按指定的条件进行排序,使用该语句后可提高查询效率,但该顺序在执行数据的增、删、改操作后,有可能无法继续保持。
- table_options:修改表选项,具体定义与CREATE TABLE语句的一样。
可以在一个ALTER TABLE语句中写入多个ADD、ALTER、DROP和CHANGE子句,中间用逗号分开。
4.重命名数据表
除了上面的ALTER TABLE命令,还可以直接用RENAME TABLE语句来更改表的名称,其语法格式如下。
RENAME TABLE tbl_name TO new_tbl_name
说明:
- tbl_name:修改之前的表名。
- new_tbl_name:修改之后的表名
5.删除数据表
当一个表不再需要时,可以将其删除。删除一个表时,表的定义、表中的所有数据以及表的索引、触发器、约束等均被删除。
如果一个表被其他表通过外键约束引用,那么必须先删除定义外键约束的表,或删除其外键约束。当没有其他表引用时,这个表才能被删除;否则,删除操作就会失败。
删除表时可以使用DROP TABLE语句,其语法格式如下。
DROP [TEMPORARY] TABLE [IF EXISTS] tbl_name [, tbl_name] ...
说明:
- tb1_name:要被删除的表名。
- IF EXISTS:避免要删除的表不存在时出现错误信息。
练一练
1.创建诚信管理论坛系统数据库中的用户表。
2.将诚信管理论坛系统数据库中的用户表的用户编号字段设为自动增长列。
3.删除诚信管理论坛系统数据库中的用户表。
任务解决
示例2.2.5 创建诚信管理论坛系统数据库中的用户表。
用户表的结构见表2.1.1,在MySQL控制台窗口中,输入以下命令,创建用户表,其结果如图2.2.8所示。
CREATE TABLE tbl_user (
uId int(11),
uName varchar(20) ,
uPass varchar(20) ,
head varchar(50) ,
regTime timestamp ,
gender smallint(6) ) ;
本例中创建的用户表仅定义了最基本的字段名和字段类型,而关于列的为空性和约束并没有给出,实际上可以通过“列定义”对列的为空性和约束进行描述。在MySQL中列定义的语法格式如下。
说明:
- col_name:表中列的名称。列名必须符合标识符的命名规则,长度不能超过64个字符,且在表中要唯一。如果有MySQL保留字必须用单引号括起来。
- type:列的数据类型,有的数据类型需要指明长度n,并用括号括起,MySQL支持的数据类型见表2.2.1。
- AUTO_INCREMENT:设置自增属性,只有整型列才能设置此属性。当插入NULL值或0到一个AUTO_INCREMENT列中时,列被设置为value+1,在这里,value是此前表中该列的最大值。AUTO_INCREMENT顺序从1开始。每个表只能有一个AUTO_INCREMENT列,并且它必须被索引。
- NOT NULL | NULL:指定该列是否允许为空。如果不指定,则默认为NULL。
- DEFAULT default_value:为列指定默认值,默认值必须为一个常数。其中,BLOB和TEXT列不能被赋予默认值。如果没有为列指定默认值,MySQL自动分配一个。如果列可以取NULL值,默认值就是NULL。如果列被声明为NOT NULL,则默认值取决于列类型。
① 对于没有声明AUTO_INCREMENT属性的数字类型,默认值是0。对于一个AUTO_INCREMENT列,其默认值是在顺序中的下一个值。
② 对于除TIMESTAMP以外的日期和时间类型,默认值是该类型适当的“零”值。对于表中第一个TIMESTAMP列,默认值是当前的日期和时间。
③ 对于字符串类型,默认值是空字符串。对于ENUM,默认值是第一个枚举值。
- UNIQUE KEY | PRIMARY KEY:PRIMARY KEY和UNIQUE KEY都表示字段中的值是唯一的。PRIMARY KEY表示设置为主键,一个表只能定义一个主键,主键一定要为NOT NULL。
- COMMENT 'string':对列的描述,string是描述的内容。
- reference_definition:指定外键所引用的表和列。
因此,带有完整列定义的创建用户表的SQL语句如下所示。
通常情况下,设置好列定义,即可较好地完成数据表的创建工作,不过MySQL中还提供了表选项,以更好地完成表的创建,其语法格式如下。
说明:
表中大多数的选项涉及的是表数据如何存储及存储在何处。多数情况下,不必指定表选项。ENGINE选项是定义表的存储引擎,存储引擎负责管理数据存储和MySQL的索引。目前使用最多的存储引擎是MyISAM和InnoDB。
- MyISAM引擎是一种非事务性的引擎,提供高速存储和检索,以及全文搜索能力,适合数据仓库等查询频繁的应用。在MyISAM中,一个table实际保存为3个文件:.frm存储表定义、.MYD存储数据和.MYI存储索引。
- InnoDB是一种支持事务的引擎。所有的数据存储在一个或者多个数据文件中,支持类似于Oracle的锁机制。一般在OLTP应用中使用较广泛。如果没有指定InnoDB配置选项,MySQL将在MySQL数据目录下创建一个名为ibdata1的自动扩展数据文件,以及两个名为ib_logfile0和ib_logfile1的日志文件。
因此,创建用户表的完整SQL语句如下所示。
示例2.2.6 将示例2.2.5所建表的UID列设为自动增长列
在MySQL控制台窗口中,输入以下命令,修改用户表中UID列的定义,其结果如图2.2.9所示。
ALTER TABLE tbl_user MODIFY COLUMN uid int(11) NOT NULL
AUTO_INCREMENT PRIMARY KEY;
示例2.2.7 删除示例2.2.5所创建的tbl_user表
在MySQL控制台窗口中,输入以下命令,修改用户表中UID列的定义,其结果如图2.2.10所示。
DROP TABLE IF EXISTS 'tbl_user';
2.2.3 创建数据约束
相关知识
为了减少输入错误和保证数据库数据的完整性,可以对字段设置约束。约束是一种命名规则和机制,即通过对数据的增、删、改操作进行一些限制,以保证数据库的数据完整性。它包括“NOT NULL”、默认值、Unique约束、主键约束和外键约束等5种机制(CHECK约束在MySQL中虽然保留了关键字,但并没有对其提供实现)。
有两种方法定义完整性约束:列约束和表约束。列约束定义在一个列上,只能对该列起约束作用。表约束一般定义在一个表的多个列上,要求被约束的列满足一定的关系。
下面分别介绍5种约束的实现。
1.NOT NULL约束
NOT NULL约束指定了这样一个规则:被约束的列不能包含NULL值,且只能是一个列约束,不能是一个表约束。当试图在一个有NOT NULL约束的列插入NULL值时,会发生错误。例如,创建用户表时,指定UID列不能为空。
CREATE TABLE USER (uid INT(11) NOT NULL);
当然也可以通过ALTER TABLE语句修改列定义,具体可参看示例2.2.6。
2.DEFAULT约束
DEFAULT约束用于向列中插入默认值。如果在操作数据时没有提供其他的值,那么会将默认值添加到记录中,DEFAULT约束也只能是一个列约束。例如,创建用户表时,指定其注册日期的默认值为当前时间。
3.UNIQUE约束
UNIQUE约束要求该列中的所有值都是唯一的。定义UNIQUE约束的列不一定需要NOT NULL约束,在一个没有NOT NULL约束的列上有多个NULL值并不违背UNIQUE约束。实际上,NULL值不等于任何值,包括NULL值。每一个UNIQUE列约束必须是针对没有UNIQUE或PRIMARY KEY约束的列。MySQL为UNIQUE约束提供了列级和表级的双重支持。例如创建一个姓名不可重复的用户表,既可以使用列级约束,写成:
也可以使用表级约束,写成:
4.PRIMARY KEY约束
PRIMARY KEY列约束也称主键约束,用于规定表中被约束的列只能包含唯一的非NULL值。具有PRIMARY KEY约束的列不必指定NOT NULL约束。在一个表中只能有一个PRIMARY KEY约束。PRIMARY KEY应该定义在表上没有定义任何UNIQUE约束的列上,因为如果同时定义了PRIMARY KEY约束和UNIQUE约束,就有可能会创建重复的索引或完全等价的索引,从而增加运行时不必要的开销。MySQL也为主键约束提供了双重支持,既可以使用列级约束,写成:
也可以使用表级约束,写成:
但不能同时使用列级约束和表级约束定义PRIMARY KEY,而且如果需要2个以上的字段作为联合主键时,只能使用表级约束进行定义。
5.FOREIGN KEY约束
FOREIGN KEY约束也称外键约束,用于建立表间关系,它表明被外键修饰的字段在另一张表中(也称主表)是主关键字,使用外键可以保证数据的一致性和完整性。MySQL为外键提供了有限的支持,目前只有InnoDB引擎支持外键,它要求所有关联表都必须是InnoDB型,而且不能是临时表,同时只支持表级约束实现,其定义语法格式如下。
练一练
1.简述5种约束的实现方式。
2.完成电子商务网站数据库的创建。
3.创建下列某图书管理系统的数据库、表和约束。
模拟开发适合学校使用的小型图书管理系统的数据库BookManagement,需要建立5个关系表,分别为图书明细表、图书种类表、读者明细表、借阅记录表、罚款记录表。
图书种类表(Booktype):记录所有的图书种类,如历史、政治,每条记录代表一种类型的图书,具体见表2.2.2。
图书明细表(BookInfo):用途为记录所有图书的信息,每条记录代表一本图书,包括库存册数、借出数随借书、还书的行为而改变,具体见表2.2.3。
读者明细表(Readinfo):记录所有读者的信息,每条记录代表一个读者,具体见表2.2.4。
借阅记录表(borrowinfo):记录所有的借阅记录信息,每条记录代表一个读者借阅了一本书,借阅图书时如果这个读者借了同一本书而且还没归还,就不允许再借这本书,具体见表2.2.5。
罚款记录表(Fineinfo):记录所有的罚款记录信息,每条记录代表一个读者借阅了一本书超出有效期后,将按照每天0.1元的金额进行罚款,具体见表2.2.6。
任务解决
示例2.2.8 MySQL中的外键约束示例
(1)在MySQL控制台窗口中,输入以下命令,创建USER表。为简化操作,该表中仅定义一个uid列,表示用户编号,将其设为主键,同时注意使用Innodb存储引擎进行存储。
(2)在MySQL控制台窗口中,输入以下命令,创建TOPIC表。为简化操作,该表中仅定义一个tid列,表示帖子编号,将其设为主键,同时使用uid列记录发帖人,将该列设为外键,引用USER表中的uid列。注意使用Innodb存储引擎进行存储。
(3)在MySQL控制台窗口中,输入以下命令,在USER表中插入1条记录。
(4)在MySQL控制台窗口中,输入以下命令,在TOPIC表中插入1条记录,表示有1个用户发帖。
请注意,由于已将TOPIC表与USER表建立了外键关联,因此要求帖子表中的用户必须是用户表中已有的用户,如不是,则报错。所有操作运行结果如图2.2.11所示。
示例2.2.9 完成诚信管理论坛中用户表、版块表和帖子表的创建,并建立外键关联。
(1)创建用户表并将UID设为主键,其SQL语句如下所示。
(2)创建版块表,并将版块编号设为主键,其SQL语句如下。
(3)创建帖子表,并将帖子编号设为主键,同时建立与用户表和版块表的关联关系,其SQL语句如下。
2.3 诚信管理论坛数据库编程与管理
数据库创建完成后,最重要的工作就是在数据库中查询需要的数据,并对数据进行增加、修改和删除操作,为了便于高效率的工作,有时还需要利用存储过程和触发器来实现业务操作。本节将介绍以下主要内容。
- 数据管理语句。
- 数据查询语句。
- 存储过程和触发器。
2.3.1 数据管理语句
相关知识
创建数据库和表后,需要对表中的数据进行操作。包括插入、删除和修改操作,可以通过SQL语句来实现,下面介绍如何实现。在进行操作前要使用USE语句将所在的数据库指定为当前数据库。
1.插入数据
一旦创建了数据库和表,下一步就是向表中插入数据。通过INSET或REPLACE语句可以向表中插入一行或多行数据。
(1)INSERT语句。
INSERT语句的语法格式如下。
说明:
- tbl_name:表名。
col_name:需要插入数据的列名。如果要给全部列插入数据,列名可以省略。如果只给表的部分列插入数据,则需要指定 这些列。对于没有指出的列,它们的值根据列默认值或有关属性来确定。MySQL的处理方式如下:
(1)具有INDENTITY属性的列,系统生成序号值来唯一标志列。
(2)具有默认值的列,其值为默认值。
(3)没有默认值的列,若允许为空值,则其值为空值;若不允许为空值,则出错。
(4)类型为timestamp的列,系统自动赋值。VALUES子句:包含各列需要插入的数据列表,数据的顺序要与列的顺序相对应。若tbl_name后不给出列名,则在VALUES子句中要给出每一列(除INDENTITY和timestamp类型的列)的值,如果列值允许为空,则值必须设为NULL,否则将会报错。
(1)expr:可以是一个常量、变量或一个表达式,也可以是空值NULL,其值的数据类型要与列的数据类型一致。例如,列的数据类型为INT,而插入的数据是a,就会出错。当数据为字符型时要用单引号括起来。
(2)使用关键词DEFAULT,明确地将所对应的列设为默认值,这样可以使语句更规范。
使用INSERT语句除了可以向表中插入一行数据外,也可以插入多行数据,插入的行可以给出每列的值,也可只给出部分列的值,还可以向表中插入其他表的数据。通过使用INSERT INTO...SELECT...,可以快速地从一个或多个表中向一个表插入多行,其语法格式如下。
(2)REPLACE语句。
如果要使插入的记录中含有与原有记录中PRIMARY KEY或UNNIQUE KEY相同的列值,则INSERT语句就无法插入此行。例如,uId是用户表中的主键列,当表中已存在uId为1的用户后,再次插入uId为1的数据时,INSERT语句就会报错。不过,在MySQL中提供了REPLACE语句,可以使用户再次插入此类数据,使用REPLACE语句可以在插入数据之前将与新记录冲突的旧记录删除,从而使新记录能够正常插入。REPLACE语句的用法和INSERT语句基本相同,在某种意义上,REPLACE语句的功能更类似于修改功能。
2.修改数据
要修改表中的一行数据,可以使用UPDATE语句来修改一个表或多个表,其语法格式如下。
说明:
- SET子句:根据WHEREE中指定的条件对符合条件的数据进行修改。如果没有WHERE子句,则修改表中的所有记录。col_name1、col_name2...为要修改的列,expr1、expr2…可以是常量、变量或表达式。可同时修改多个列,中间用逗号隔开。
3.删除数据
DELETL语句或TRUNCATE 语句可以用于删除表中的一行或多行数据。
(1)DELETE语句。
从单个表中删除数据,其语法格式如下。
说明:
- QUICK关键字:用于加快部分类型删除操作的速度。
- FROM子句:用于指明从何处删除数据,tbl_name为待删除数据的表的名称,注意在MySQL中该关键字不可省略。
- WHERE子句:用于指明删除时的过滤条件,如果不指明,则默认为删除全部数据。
- ORDER BY子句:各行按照指定的顺序删除,此子句只在与LIMIT联用时才起作用。
- LIMIT子句:用于控制删除的最多记录数。
(2)TRUNCATE语句。
使用TRUNCATE语句将删除指定表中的所有数据,因此也称其为清除表数据语句,其语法格式如下。
说明:
由于TRUNCATE语句将删除表中的所有数据,且无法恢复,因此必须小心使用。
TRUNCATE语句在功能上与不带WHERE子句的DELETE语句相同,二者均删除表中的全部记录,但TRUNCATE比DELETE速度快,且使用的系统和事务日志资源少。DELETE语句每次删除一条记录,都需在事务日志中记录。而TRUCATE语句通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录释放操作。使用TRUNCATE语句,AUTO_INCREMENT计数器将被重新设置为初始值。
对于建立了视图和索引的表不建议使用TRUNCATE语句。
练一练
1.请在用户表中插入以下数据。
2.删除上述用户表中的数据。
任务解决
示例2.3.1 向用户表中插入一条数据,其值如下。
在MySQL中还提供了INSERT语句另一种形式,可以使用SET子句来逐列指明所插入的值,其语法格式如下:
因此示例2.3.1的插入语句也可以写成如下形式。
示例2.3.2 将用户表中uId为1的用户性别修改为男性。
示例2.3.3 将用户表中uId为3的记录删除。
2.3.2 数据查询语句
相关知识
使用数据库和表的主要目的是存储数据以便在需要时进行检索、统计或组织输出,通过SQL语句的查询可以从表中迅速方便地检索数据。SQL中的SELECT语句用于从数据库表或视图中查询数据,并且可以从一个或多个表或视图中选择一个或多个行或列,SELECT语句的语法格式如下:
说明:
SELECT语句的完整语法格式比较复杂,其中主要子句包括select子句、from子句、where子句、group by子句、having子句、order by子句和LIMIT子句。下面先对语法格式进行简单分析,然后再逐个子句介绍,SELECT关键字的后面可以使用如下选项。
- ALL | DISTINCT | DISTINCTROW:这几个选项指定重复行是否被返回。如果没有指定,则默认值为ALL(返回所有匹配的记录)。DISTINCT和DISTINCTROW是同义词,用于消除结果集中的重复记录。
- HIGH_PRIORITY、STRAIGHT_JOIN和以SQL开头的选项:都是MySQL对标准SQL的扩展,这些选项在多数情况下可以选择不使用。HIGH_PRIORITY选项表示给予SELECT语句更高的优先权,使查询立刻执行,加快查询速度。STRAIGHT_JOIN用于促使MySQL优化器把表联合在一起,加快查询速度。
- SQL_SMALL_RESULT:可以与GROUP BY或DISTINCT同时使用,用于在查询结果集较小的情况下,通知MySQL使用快速临时表来储存获得的结果集。
- SQL_BIG_RESULT:可以与GROUP BY或DISTINCT同时使用,用于在查询结果集较大的情况下,通知MySQL不要使用临时表,而是先进行分类,并直接使用以磁盘为基础的临时表。
- SQL_BUFFER_RESULT:将查询所获得的结果集放入一个临时表中,从而加快解除表锁定,因此,可以提高对客户端的响应速度。
- SQL_CACHE | SQL_NO_CACHE:用于控制是否缓存查询结果。
- SQL_CALC_FOUND_ROWS:计算忽略LIMIT子句的查询结果记录数。
- INTO OUTFILE 'file_name' | INTO DUMPFILE 'file_name'| INTO var_name:用于控制查询结果是否需要输出到文件,导出为备份或保存到变量中。
从基本语法格式中可以看出,最简单的SELECT语句是SELECT select_expr,利用它可以直接进行MySQL所支持的任何运算。例如,SELECT1+1将返回2。同时要注意的是:所有使用的子句必须按语法说明中显示的顺序严格排序。例如,HAVING子句必须位于ORDER BY子句之前,GROUP BY子句之后。下面以诚信管理论坛数据库的查询为例,介绍一些SELECT语句的常见用法,假定诚信管理论坛数据库中有如图2.3.1所示的数据。
1.SELECT子句
(1)选择指定的列。
SELECT语句中的SELECT select_expr用来指定需要查询的列。使用SELECT语句选择一个表中的某些列,各列名之间要以逗号分隔。
(2)查询全部列。
可以在SELECT子句中使用“*”,表示查询所有字段。
(3)定义列别名。
可以在SELECT子句中使用AS子句来定义查询结果的列别名,其语法格式如下。
别名是字母或数字时,可以省略定界符“’”,但别名中含有如空格等特殊字符时,必须使用定界符“’”,同时要注意在WHERE子句中不能使用列别名。例如,下述查询是非法的。
(4)计算列值。
使用SELECT对列进行查询时,在结果中可以输出对列值计算后的值,即SELECT子句可使用表达式。
(5)替换查询结果。
在查询时,有时需要对查询结果进行替换,如在诚信管理论坛数据库的用户表中用户性别采用整数存储,其值为1表示男性,其值为2表示女性,因此在查询性别时,希望将查询结果显示为男或女,而不是存储的1和2。要替换查询结果中的数据,可以使用查询中的CASE表达式,格式如下。
(6)消除重复结果。
在查询时,有时会出现重复记录,如用户表中有2个用户名为“wen”的用户,可以使用DISTINCT或DISTINCT ROW来消除重复记录。
(7)聚合函数。
SELECT子句的表达式中还可以包含聚合函数。聚合函数常常用于对一组值进行计算,然后返回单个值。除COUNT函数外,聚合函数都会忽略空值。聚合函数通常与GROUPBY子句一起使用。如果SELECT语句中有一个GROUP BY子句,则这个聚合函数对所有列起作用,如果没有,则SELECT语句只产生一行作为结果。表2.3.1列出了MySQL中的聚合函数。
由于篇幅限制,这里仅以最常使用的COUNT函数为例,介绍聚合函数的使用。COUNT函数用于统计组中满足条件的行数或总行数,返回SELECT语句检索到的记录中非NULL L值的数目,若找不到匹配的行,则返回0,其语法格式如下。
其中,expression是一个表达式,其数据类型是除BLOB或TEXT之外的任何类型,ALL表示对所有值进行运算,DISTINCT表示去除重复值,默认为ALL。使用COUNT(*)时将检索行的总数目。
2.FROM子句
SELECT的查询对象由FROM子句指定,其语法格式如下。
其中table_reference为
说明:
table_reference用于指明要查询的表或视图。
- tbl_name:为要查询的表名,与列别名一样,可以使用As选项为表指定别名。
- tbl_name_alias为表别名。表别名主要用在相关子查询及连接查询中。如果FROM子句指定了表别名,则SELECT语句中的其他子句都必须使用表别名来代替原始表名。当同一个表在SELECT语句中多次被提到时,就必须使用表别名。
- {USE|IGNORE|FORCE} INDEX:USE INDEX表示将使用索引来执行查询,IGNORE INDEX表示查询时不使用索引,FORCE INDEX的作用与USE INDEX类似,表示在无法使用USE INDEX时,将强制使用表扫描来执行查询。
FROM子句中可以只包含一个表,也可以引用多个表,当只有一个表时,如果查询的表不属于当前数据库,还需要在表前加上数据库的名称。例如,引用诚信管理论坛的用户表,可以使用如下语句。
SELECT * FROM cxbbs.tbl_user;
如果要在不同的表中查询数据,则必须在FROM子句中指定多个表,这需要使用连接,连接的方式有两种:全连接和JOIN连接。全连接是指将各个表用逗号分隔,这样FROM子句会生成一个新表,新表的记录是各表的笛卡儿积,因此通常要使用WHERE子句来设定连接条件,这样的连接即为等值连接。
JOIN连接即是使用JOIN关键字的连接,主要分为3种:内连接、外连接和交叉连接。
(1)内连接。
内连接使用INNER关键字,是系统默认的连接方式,因此可以省略INNER关键字,使用内连接。
JOIN关键字根据ON关键字所指定的连接条件,合并两个表,并返回满足条件的记录。作为特例,可以将一个表与它自身进行连接,称为自连接。若要在一个表中查找具有相同列值的行,则可以使用自连接。使用自连接时需为表指定两个别名,且对所有列的引用均要有别名限定。
(2)外连接。
外连接使用OUTER关键字,包括以下几种。
- 左外连接(LEFT OUTER JOIN):除返回符合匹配条件的记录外,还返回左表中存在但右表中不存在的记录,对于这样的记录,从右表中选择的列将设为NULL。
- 右外连接(RIGHT OUTER JOIN):除返回符合匹配条件的记录外,还返回右表中存在但左表中不存在的记录,对于这样的记录,从左表中选择的列将设为NULL。
- 自然连接(NATURAL JOIN):自然连接与使用了ON条件的内连接相同。
(3)交叉连接。
使用了CROSS JOIN关键字的连接是交叉连接,交叉连接实际上是将两个表进行笛卡儿积运算。
3.WHERE子句
WHERE字句用于提供查询条件,它必须紧跟在FROM子句之后,在SELECT子句执行时,对FROM子句进行判定,WHERE子句进行的判定运算包括比较运算、模式匹配、范围比较、空值比较和子查询。
(1)比较运算。
比较运算符用于比较两个表达式的值,MySQL支持的比较运算符有=(等于)、<(小于)、<=(小于等于)、>(大于)、>=(大于等于)、<=>(空安全等于)、<>(不等于)、!=(不等于)。
比较运算的语法格式为
其中,expresion是除TEXT和BLOB类型外的表达式。
当两个表达式值均不为空值(NULL)时,除了“<=>”运算符,其他比较运算返回逻辑值"TRUE(真)或FALSE(假);而当两个表达式值中有一个为空值或都为空值时,将返回UNKOWN。“<=>”(空安全等于)是MySQL特有的等于运算符,当两个表达式彼此相等或都等于空值时,它的值为TRUE,其中有一个空值或都是非空值但不相等时,其值为FALSE,没有UNKNOWN的情况。比较运算符的结果还可以通过逻辑运算符进行组合,形成复杂的条件表达式。
(2)模式匹配。
模式匹配包括LIKE运算符和REGXP运算符两类,其中LIKE运算符用于指出一个字符串是否与指定的字符串相匹配,其运算对象可以是CHAR、VARCHAR、TEXT、DATETIME等类型的数据,返回逻辑值TRUE或FALSE。使用LIKE进行模式匹配时,常使用特殊符号“ ”和“ % ”进行模糊查询,“%”代表0个或多个字符,“”代表单个字符。还可以使用ESCAPE关键字指定查询时使用的转义字符。
除了LIKE运算符,MySQL还提供了REGXP运算符用来执行更复杂的字符串比较运算,REGXP是正则表达式(Regular Expression)的缩写,限于篇幅,请读者自行参看相关文献。
(3)范围比较。
用于范围比较的关键字有两个:BETWEEN和IN。当要查询的条件是某个值的范围时,可以使用BETWEEN关键字。BETWEEN关键字指出查询范围,其格式如下。
在不使用NOT时,如果expression的值在expression1和expression2之间,返回TRUE,否则返回FALSE。如果使用NOT,则返回值相反。注意expression1的值要小于expression2的值。
使用IN关键字可以指定一个值表,值表中列出所有可能的值,当与值表中的任何一个匹配时,返回TRUE,否则返回FALSE。使用IN关键字指定值表的格式如下。
(4)空值比较。
当需要判定一个表达式的值是否为空值时,使用IS NULL关键字,其格式如下。
当不使用NOT时,若表达式expression的值为空值,返回TRUE,否则返回FALSE;当使用NOT时,结果相反。
(5)子查询。
子查询是一条包含在另一条SELECT语句里的SELECT语句。外层的SELECT语句叫外部查询,内层的SELECT语句叫内部查询(或子查询)。通常,任何允许使用表达式的地方都可以使用子查询。
包括子查询的SELECT语句主要采用以下3种格式中的一种。
① 使用IN的子查询。 使用IN(或NOT IN)的子查询,返回的查询结果是一列零值或更多值。子查询返回结果之后,外部查询可以使用这些结果。其格式如下。
② 使用比较运算符的子查询。
子查询可由一个比较运算符引入。比较运算符可以是=、<>、>、<、>=、<=、!>、!<等。其格式如下。
其中,comparison_operator为比较运算符,ALL表示子查询subquery返回的查询结果中的全部值,ANY表示子查询中的任意一个值。
③ 使用EXISTS的子查询。
使用EXISTS(或NOT EXISTS)关键字引入一个子查询时,相当于进行一次存在测试。外部查询的WHERE子句测试子查询返回的行是否存在。子查询实际上不产生任何数据,它只返回TRUE或FALSE值。其格式如下。
4.GROUP BY子句
GROUP BY子句主要用于根据字段对行分组。GROUP BY子句的语法格式如下。
说明:
GR0UP BY子句后通常包含列名或表达式。MySQL对GROUP BY子句进行了扩展,可以在列的后面指定ASC(升序)或}}(降序)。GROUP BY可以根据一个或多个列进行分组,也可以根据表达式进行分组,经常和聚合函数一起使用。
5.HAVING子句 使用HAVING子句的目的与WHERE子句类似,不的是WHERE子句用来在FROM子句之后选择行,而HAVING子句用来在GR0UP BY子句后选择行。其语法格式如下。
其中where_definition是选择条件,条件的定义和WHERE子句中的条件类似,但HAVING子句中的条件可以包含聚合函数,而WHERE子句中则不可以。
SQL标准仅要求HAVING子句必须引用GROUP BY子句中的列或聚合函数中的列,但MySQL对此提供了扩展实现,允许在HAVING子句中引用SELECT子句和外部子查询中出现的字段。
6.ORDER BY子句
SELECT语句的查询结果,如果不使用ORDER BY子句,结果中记录的顺序是不可预料的。而使用ORDER BY子句后可以保证结果中的行按给定的顺序排列。ORDER BY子句的语法格式如下。
说明:
ORDER BY子句后可以是列、表达式或正整数。使用正整数表示按SELECT子句中该位置上的列进行排序。例如,使用ORDER BY3表示对SELECT的子句中的第3个字段进行排序。关键字ASC表示升序,DESC表示降序,系统默认值为ASC。
7.LIMIT子句
LIMIT子句是SELECT语句的最后一个子句,主要用于限制被SELECT语句返回的行数,其语法格式如下。
说明:
语法格式中的offset和row_count都必须是非负的整数常数,offset表示返回从第几条记录开始,row_count表示显示的记录数。例如,“LIMIT 5”表示返回SELECT语句的查询结果中最前面的5行,而“LIMIT 3,5”则表示从返回第4行开始的5条记录。值得注意的是,offset的起始数是0而不是1。
8.UNION语句
使用UNION语句可以把来自多条SELECT语句的结果合并到一个结果集中,其语法格式如下。
说明:
SELECT语句为常规的选择语句,但必须遵守以下规则。
- 每条SELECT语句所查询的列应确保其数目一致,且对应位置的列应具有相同的数据类型。例如,被第一个语句选择的第一列应和被其他语句选择的第一列具有相同的数据类型。
- ORDERBY和LIMIT子句只能在整个语句最后指定,同时还应对单个SELECT语句加圆括号。排序和限制行数对整个最终结果起作用。
- 只有最后一条SELECT语句可以使用INTO OUTFILE选项。
使用UNION时,第一条SELECT语句中所使用的列名称被用于最终返回结果集的列名称。而且MySQL默认会从最终结果中去除重复行,要返回全部记录,则可以指定关键字ALL。
任务解决
示例2.3.4 查询发帖用户的用户名、性别和注册时间。
SELECT uName, gender, regtime FROM tbl_user;
其结果如图2.3.2所示。
示例2.3.5 查询用户表中的全体用户的详细信息。
SELECT * FROM tbl_user;
其结果如图2.3.3所示。
示例2.3.6 使用别名显示用户的用户名、性别和注册时间。
SELECT uName '用户名', gender AS '性别', regtime AS '注册时间' FROM tbl_user;
其结果如图2.3.4所示。
示例2.3.7 给论坛用户统一增加“cx”前缀。
SELECT CONCAT('cx',uName) username FROM tbl_user ;
说明:
CONCAT函数用于连接字符串,MySQL不支持字符串的“+”运算符,其结果如图2.3.5所示。
示例2.3.8 显示用户表中的用户名和性别,要求将性别的查询结果替换为“男”或“女”。
其结果如图2.3.6所示。
示例2.3.9 显示用户表中用户名不同的用户。
示例2.3.10 显示用户表的用户数。
SELECT COUNT(*) FROM tbl_user;
其结果如图2.3.8所示。
示例2.3.11 显示帖子的标题和发帖人的名称。
SELECT uName,title
FROM tbl_user AS u,tbl_topic AS t
WHERE u.uId=t.uId;
其结果如图2.3.9所示。
示例2.3.12 使用内连接显示某个帖子的发帖人和标题。
SELECT uName,title
FROM tbl_topic t INNER JOIN tbl_user u ON t.uId = u.uId;
其结果如图2.3.10所示。
示例2.3.13 显示所有版块的父版块的名称。
SELECT a.boardName AS '版块名',b.boardName AS '父版块名'
FROM tbl_board AS a JOIN tbl_board AS b ON a.parentId = b.boardId;
其结果如图2.3.11所示。
如果要连接的表中有同名的列,并且连接条件就是列名相同,那么ON条件也可以换成USING子句,如示例2.3.9也可以写成以下形式。
SELECT uName,title
FROM tbl_topic JOIN tbl_user
USING (uId);
示例2.3.14 显示版块名中含有“Java”字符的版块。
SELECT * FROM tbl_board
WHERE boardName LIKE '%java%';
其结果如图2.3.12所示。
示例2.3.15 显示版块名中第2个字符为“a”的版块。
SELECT * FROM tbl_board
WHERE boardName LIKE '_a%';
其结果如图2.3.13所示。
示例2.3.16 显示诚信管理论坛中2011年3月注册的全部用户。
SELECT * FROM tbl_user
WHERE regTime BETWEEN '2011-03-01' AND '2011-04-01';
其结果如图2.3.14所示。
示例2.3.17 显示诚信管理论坛中Java技术和.NET技术版块下的所有子版块。
说明:
.NET技术版块的编号为1,java技术的版块编号为2。
SELECT * FROM tbl_board
WHERE parentId IN (1,2);
其结果如图2.3.15所示。
示例2.3.18 列出诚信管理论坛中用户名为“qq”的用户发过帖子的全部版块名称。
此例中,首先执行内部查询
SELECT boardId FROM tbl_topic t,tbl_user u
WHERE t.uId=u.uId AND u.uName='qq'
子查询从帖子表中首先查出qq用户曾发过帖子的全部版块编号;然后再执行外部查询SELECT boardName FROM tbl_board WHERE boardId IN(内查询的值)语句查询出最后结果。其结果如图2.3.16所示。
示例2.3.19 统计帖子表中各版块的发帖数量。
SELECT boardId,COUNT(topicId)
FROM tbl_topic
GROUP BY boardId;
其结果如图2.3.17所示。
示例2.3.20 显示发帖数量超过1条的全部版块。
SELECT boardId,COUNT(topicId) as '发帖量'
FROM tbl_topic
GROUP BY boardId
HAVING COUNT(topicId)>1;
其结果如图2.3.18所示。
示例2.3.21 按注册时间降序显示用户表的数据。 SELECT * FROM tbl_user ORDER BY regTime DESC;
当对空值排序时,ORDER BY子句将空值作为最小值对待,按升序排列时将空值放在最上方,降序放在最下方。其结果如图2.3.19所示。
示例2.3.22 显示最新注册的3个用户。
SELECT * FROM tbl_user
ORDER BY regTime DESC
LIMIT 3;
其结果如图2.3.20所示。
示例2.3.23 显示C#语言版块和JAVA基础版块下的全部帖子(使用UNION语句实现)。
说明:
C#语言版块的版块编号为5,JAVA基础版块的版块编号为8。
SELECT topicId,boardId,publishTime,title FROM tbl_topic
WHERE boardId=5
UNION
SELECT topicId,boardId,publishTime,title FROM tbl_topic
WHERE boardId=8;
其结果如图2.3.21所示。
2.4 实践习题
1.INSERT语句和REPLACE语句有何不同,请设计相关试验。
2.简述DELETE语句和TRUNCATE语句的区别。
3.说明SELECT各子句的作用。
4.简述视图的作用与特点。
5.可以使用( )语句创建数据库。
A.NEW DATABASE
B.BUILD DATABASE
C.INSERT DATABASE
D.CREATE DATABASE
6.使用SQL语句进行分组检索时,为了去掉不满足条件的分组,应当( )。
A.使用WHERE子句
B.在GROUP BY后面使用HAVING子句
C.先使用WHERE子句,再使用HAVING子句
D.先使用HAVING子句,再使用WHERE子句
7.假定有以下企业管理的员工管理数据库,数据库名为YGGL,其中主要有如表2.3.2~表2.3.7所示的表及其样本数据。
请完成以下操作。
(1)创建数据库YGGL。
(2)创建员工信息表、部门表和薪水表。
(3)插入各表的样本数据。
(4)在员工信息表和薪水表中,删除员工编号为“000001”的数据。
(5)将员工编号为“020018”的记录的部门号改为4。
(6)根据员工信息样本数据表和薪水样本数据表,重新插入员工编号为“000001”的数据。
(7)使用REPLACE语句向部门插入一条数据,其部门号为“1”,名称为“广告部”,备注为“负责广告业务”。
(8)将员工号为011112的职工收入改为2890。
(9)将所有职工收入增加100。
(10)删除所有收入大于2500的员工信息。
(11)查询员工表中的全部记录。
(12)查询每个员工的地址和电话。
(13)查询员工编号为“000001”的员工地址和电话。
(14)查询月收入高于2000的员工号码。
(15)查询1970年以后出生的员工姓名和地址。
(16)查询财务部所有的员工编号和姓名。
(17)查询所有女员工的地址和电话,需指定显示的列标题为姓名、地址、电话。
(18)查询所有男员工的姓名和出生日期,要求各标题用中文表示。
(19)获得员工总数。
(20)计算所有员工收入的平均数。
(21)获得员工信息表中最大的员工编号。
(22)计算所有员工的总支出。
(23)找出所有姓王的员工的部门编号。
(24)找出员工编号中倒数第2个数字为0的员工的姓名、地址和学历。
(25)找出所有收入在2000~3000的员工编号。
(26)找出所有在部门编号为“1”或“2”中工作的员工编号。
(27)查找在财务部工作的员工信息。
(28)查找所有收入在2500以下的员工信息。
(29)查找财务部中比所有研发部员工年龄都大的员工信息。
(30)查找研发部中比所有财务部员工收入都高的员工信息
(31)显示所有员工的基本信息和薪水情况。
(32)显示每个员工的基本信息及其工作的部门信息。
(33)显示“王林”所在的部门名称。
(34)统计员工信息表中男性和女性的人数。
(35)按部门列出部门的员工人数。
(36)按员工学历分组,列出本科、大专和硕士的人数。
(37)显示员工数超过2人的部门名称和部门人数。
(38)按员工收入从多到少显示员工的基本信息和收入。
(39)按员工的出生日期从小到大显示员工信息。
(40)显示收入最高的5位员工的基本信息和收入。
(41)创建存储过程,要求当一个员工的工作年份大于6年时,将其转到经理办公室工作。
(42)创建触发器,要求当员工信息表中删除一个员工信息时,同时删除员工薪水表中对应的薪水信息。
2.5 项目总结
本项目介绍数据库的设计与实现,重点介绍了数据库的建模技术和使用MySQL进行数据库管理的相关知识,主要内容如下。
1.数据库建模技术
数据库设计的主要目的是将现实世界中的事物及联系用数据模型(Data Model,DM)描述,即信息数据化。数据库建模主要包括建立数据库的概念模型和物理模型。概念模型设计的主要工作是设计数据库的实体-关系模型,物理模型设计的主要任务是将实体-关系模型转换为关系数据库模型。
2.数据库的实现
主要介绍了数据库管理的基本操作,包括查看、创建、使用、修改、删除操作,同时介绍了对数据表管理的基本操作,包括查看、创建、修改、重命名、删除操作,最后介绍了“NOT NULL”、缺省值、Unique约束、主键约束和外键约束等5种数据约束的创建。
3.数据库管理与编程
主要介绍了INSERT、REPLACE、UPDATE、DELETE、TRUNCATE等用于数据插入、修改与删除的基本命令,详细介绍了SELECT查询语句,最后对存储过程和触发器的创建和使用进行了介绍。
2.6 专业术语
- Data Model(DM):数据模型,就是现实世界的模拟,通常数据模型分成两大类:一类是按用户的观点来对数据和信息建模,称为概念模型或信息模型;另一类是按计算机系统的观点对数据建模,主要包括网状模型、层次模型、关系模型等。
- 实体(Entity):客观存在并可以区分的事物。
- 属性(Attribute):实体所具有的某一特性称。
- 码(Key):能唯一标识实体的属性的集合。
- 关系(Relation):实体集合间存在的相互联系。
- E-R图:实体-关系模型图, E-R模型是由Peter Chen在1976年引入的,它使用实体(Entity)和关系(Relation)来模拟现实世界,E-R图可以将数据库的全局逻辑结构图形化表示,它是从计算机角度出发来对数据进行建模。
- 主键(Primary Key):是实体中的一个或多个属性,它的值用于唯一标识一个实体对象。
2.7 拓展提升
存储过程和触发器
自MySQL5.0开始,MySQL开始支持存储过程、存储函数、触发器和事件。也就是说,MySQL的版本要在5.0以上才能创建上述对象。本节将讨论其中的存储过程和触发器。
1.存储过程
存储过程最初是为了提高数据库在网络中的处理性能而提出的,但今天,存储过程已经是现代关系数据库的重要特性之一,绝大多数企业级DBMS产品都提供了存储过程性能。存储过程具有高速、可重用、减少网络拥挤、安全等优点。
存储过程也是数据库对象之一,其实质上是一段事先定义好的代码,由声明式的SQL语句(如CREATE、UPDATE和SELECT等语句)和过程式SQL语句(如IF THEN ELSE语句)组成,可以由程序、触发器或者另一个存储过程来调用,执行代码段中的SQL语句。
(1)创建存储过程。
创建存储过程可以使用CREATE PROCEDURE语句,要在MySQL 5.1中创建存储过程,必须具有相应权限,其语法格式如下。
说明:
- sp_name:存储过程的名称,默认在当前数据库中创建。需要在特定数据库中创建存储过程时,要在名称前面加上数据库的名称,格式为db_name.sp_name。值得注意的是,这个名称应当尽量避免与MySQL的内置函数同名,否则会发生错误。
- proc_parameter:存储过程的参数,param_narne为参数名,type为参数的类型,当有多个参数时中间用逗号隔开。存储过程可以有0个、1个或多个参数。MySQL存储过程支持3种类型的参数:输入参数、输出参数和输入/输出参数,关键字分别是IN、OUT和INOUT。如果需要向存储过程传递数据可使用输入参数,如果需要从存储过程中返回数据则可使用输出参数,而输入/输出参数既可以充当输入参数也可以充当输出参数。存储过程也可以不加参数,但名称后面的括号不可省略。要注意的是:参数的名称不能与列的名称相等,否则虽然不会返回出错消息,但存储过程中的SQL语句会将参数名看做列名,从而引发不可预知的结果。
- routing-body:表示存储过程的主体部分,也叫做存储过程体,里面包含了在过程调用时必须执行的语句,这个部分总是由BEGIN开始,以END结束,当存储过程中只有一条SQL语句时,可省略BEGIN-END。
- Characteristic:表示存储过程的特征,感兴趣的读者可自行参考相关资料。
在开始创建存储过程之前,先介绍一个很实用的命令,即DELIMITER。在MySQL中,服务器处理语句时是以分号为结束标志的。但在创建存储过程时,由于存储过程中可能包含多条SQL语句,而每个SQL语句都是以分号为结尾的,这时服务器处理程序时遇到第一个分号就会认为程序结束,这肯定是不行的。所以这里使用DELIMITER命令将MySQL语句的结束标志修改为其他符号。DELIMITER的格式如下。
DELIMITER <结束标志>
结束标志是用户自定义的特殊字符,如“##”,但要注意要避免使用反斜杠(“\”)字符,因为它是MySQL的转义字符。
示例2.7.1 存储过程示例。
说明:
该存储过程首先在用户表中插入一条用户编号为10的用户,随即将其显示出来,然后删除该记录。其结果如图2.7.1所示。
要想查看数据库中的存储过程列表,可以使用SHOW PROCEDURE STATUS命令。要查看某个存储过程的具体信息,可使用SHOW CREATE PROCEDURE sp_name,其中sp_name是存储过程的名称。
(2)执行存储过程。
存储过程创建完成后,可以在程序、触发器或者存储过程中被调用,但是都必须使用CALL语句,其语法格式如下。
CALL sp_name ([parameter[,...]])
说明:
sp_name为存储过程的名称,如果要调用某个特定数据库的存储过程,则需要在前面加上该数据库的名称。parameter为调用该存储过程使用的参数,其个数和类型取决于要调用的存储过程。
示例2.7.2 执行示例2.7.1所创建的存储过程。
说明:
首先显示用户表中的数据,其中不存在用户编号为10的用户。然后执行存储过程,显示了uId为10的用户,再查看用户表,可以发现该用户已经被删除了,证明该存储过程已成功执行。其结果如图2.7.2所示。
(3)修改存储过程。
使用ALTER PROCEDURE语句可以修改存储过程,其语法格式如下。
ALTER PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
(4)删除存储过程。
存储过程创建后需要将其删除时使用DROP PROCEDURE语句。在此之前,必须确认该存储过程没有任何依赖关系,否则会导致其他与之关联的存储过程无法运行,其语法格式如下。
DROP PROCEDURE [IF EXISTS] sp_name
说明:
sp_name是要删除的存储过程的名称。IF EXISTS子句是MySQL中特有的功能,如果存储过程存在则删除,否则不执行该语句,使用该子句,可防止错误出现。
示例2.7.3 删除示例2.7.3创建的存储过程。
其结果如图2.7.3所示。
(5)带参数的存储过程。
带参数的存储过程在实际开发中有着非常广泛的应用,下面给出一个带参数的存储过程示例。
示例2.6.4 带参数的存储过程。
说明:
本例定义了一个用于判断是否是休眠用户的存储过程,休眠用户的定义是:如果一个用户没有发过任何帖子,则为休眠用户,否则为活跃用户。
第01行改变命令结束标记为“##”。
第02行创建存储过程,请注意这里定义了两个参数_uId与RET,其中_uId为输入参数,RET为输出参数。
第03行为存储过程的开始标记。
第04行定义了局部变量count,用于保存用户的发帖数量。
第05行统计指定用户的发帖量,并保存到count中。
第06~10行根据得到的用户发帖量,判断是否是休眠用户。
第11行为存储过程的结束标记。
第12行将命令结束标记修改为“;”。
要运行上述存储过程,可执行以下命令。
CALL procIsSleepUser(5,@RET);
SELECT @RET;
@RET表示用户变量,用于获取输出参数,整个示例的运行结果如图2.7.4所示。
2.触发器
触发器是一种特殊的存储过程,主要用于确保复杂的业务规则和实施数据完整性。触发器不像一般的存储过程,不可以使用存储过程的名称来调用或执行。当用户对指定的表进行修改(包括插入、删除或更新)时,设置于该表的触发器被自动触发。目前MySQL触发器的功能还不够全面,在以后的版本中将得到改进。
(1)创建触发器。
创建触发器可以使用CREATE TRIGGER语句,要在MySQL 5.1中创建存储过程,必须具有相应权限,其语法格式如下。
说明:
- trigger_name:触发器的名称,触发器在当前数据库中必须具有唯一的名称。如果要在某个特定数据库中创建,名称前面应该加上数据库的名称。
- trigger_timer:触发器触发的时刻,有两个选项:AFTER和BEFORE,以表示触发器是在激活它的语句之前还是之后触发。如果要在激活触发器的语句执行之后触发,通常使用AFTER选项;如果想要验证新数据是否满足使用的限制,则使用BEFORE选项。
- trigger_event:触发事件,指明激活触发程序的语句类型。其值可以是以下几种:
INSERT:插入数据时触发,如INSERT、LOAD DATA和REPLACE语句。
UPDATE:修改数据时触发,如UPDATE语句。
DELETE:删除数据时触发,如DELETE和REPLACE语句。 - tbl_name:与触发器相关的表名,只有该表的相应事件发生时才会激活触发器。同一个表不能拥有两个具有相同触发时刻和事件的触发器。例如,对于某表,不能有两个BEFORE UPDATE触发器,但可以有1个BEFORE UPDATEE触发器和1个BEFORE INSERT触发器,或1个BEFORE UPDATE触发器和1个AFTER UPDATE触发器。
- FOR EACH ROW:这个声明用来指定,对于受触发事件影响的每一条记录,都要激活触发器的动作。例如,使用一条语句向一个表中添加一组记录,触发器会对每一条记录都执行相应的触发器动作。
- trigger_stmt:触发器语句,包含触发器激活时将要执行的语句。如果要执行多个语句可使用BEGIN END复合语句结构。
在触发器中不可避免地要引用关联表中的列,MySQL触发器中的SQL语句可以使用关联表中的任意列,但不能直接使用列的名称引用,因为激活触发器的语句可能已修改、删除或添加了新的列名,而列的旧名同时存在,这样就会使系统混淆,无法确定使用的列究竟是操作之前的列,还是操作之后的列。所以,必须通过“NEW.column_name”或者“OLD.column_name”引用。NEW.column_name用来引用操作之后,也就是新记录的列,而“OLD.column_name”用来引用更新或删除前的已有记录的列。
对于INSERT语句,只有NEW是合法的;对于DELETE语句,只有OLD才合法;而UPDATE语句可以同时使用NEW或OLD。
示例2.7.5 使用触发器实现在新增用户时自动在灌水乐园版块中发布用户报道帖。
说明:
本例在用户表(tbl_user)中定义了一个AFTER INSERT触发器,以实现在新用户注册时,自动在灌水乐园版块中发布用户报道帖。
第01行首先改变命令结束标记为“##”。
第02~03行创建触发器,请注意这里定义的AFTER INSERT触发器所关联的表是tbl_user。
第04行为触发器的开始标记。
第05~09行在帖子表中插入报道帖,请注意这里使用的是INSERT语句的SET写法。第07行插入报道帖的内容,其中使用NEW.uName引用新增用户的用户名,CONCAT函数用于连接字符串。第08行设置帖子表的发帖人,使用NEW.uId引用新增用户的用户编号。
第10行为触发器的结束标记。
第12行将命令结束标记修改为“;”。
要观察上述触发器的执行结果,可执行以下命令。
INSERT INTO tbl_user VALUES (DEFAULT,'tom','12345', '2.gif',DEFAULT,'1');
SELECT * FROM tbl_topic ORDER BY publishTime DESC LIMIT 1;
整个示例的运行结果如图2.7.5所示。
触发器创建后,可以使用SHOW TRIGGERS命令查看库中的触发器。
(2)删除触发器。
与其他数据库对象的删除一样,使用DROP语句即可删除,其语法格式如下。
DROP TRIGGER trigger_name
说明:
trigger_name是要删除的触发器的名称。
示例2.7.6 删除示例2.7.6所创建的触发器
其结果如图2.7.6所示。
2.8 超级链接
[1] MySQL官方文档和用户手册:
http://dev.mysql.com/doc/
[2] 中国人民大学数据库系统概论国家精品课程
http://www.chinadb.org/
[3] PowerDesigner 官方网站
http://www.powerdesigner.de/