描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302480518丛书名: 21世纪高等学校计算机应用技术规划教材
本书可作为计算机及相关专业的本科教材,也可作为广大计算机爱好者学习数据库技术的参考书。
第1章 数据库技术基础 1
1.1 数据库基础知识 1
1.1.1 信息、数据与数据管理
1
1.1.2 数据管理技术的发展
1
1.1.3 数据库、数据库管理系统、数据库系统
2
1.1.4 数据模型
3
1.1.5 数据库系统的体系结构
6
1.2 关系数据库 7
1.2.1 关系模型
7
1.2.2 关系数据理论
10
1.3 数据库设计 14
1.3.1 数据库设计的任务、特点和基本步骤
14
1.3.2 需求分析的任务
15
1.3.3 概念结构设计
16
1.3.4 逻辑结构设计
17
1.3.5 数据库设计案例
18
1.4 主流数据库简介 21
1.4.1
SQL Server 21
1.4.2
Oracle 22
1.4.3
Sybase ASE 22
1.4.4
DB2 23
练习题
23
第2章 SQL Server 2012综述 24
2.1 SQL Server 2012概述 24
2.1.1
SQL Server的发展过程
24
2.1.2
SQL Server 2012的体系结构 25
2.1.3
SQL Server 2012的主要特性 27
2.1.4
SQL Server 2012的版本 28
2.2 SQL Server 2012的安装 29
2.2.1
SQL Server 2012安装前的准备工作 29
2.2.2 安装SQL
Server 2012 31
2.2.3 升级到SQL
Server 2012 43
2.2.4
SQL Server 2012安装成功的验证 44
2.3 SQL Server 2012的安全性 48
2.3.1
SQL Server 2012安全性综述 48
2.3.2 权限验证模式
49
2.3.3 数据库用户账号、角色和权限
50
2.4 SQL Server 2012工具 51
2.4.1 配置SQL
Server 2012服务器
51
2.4.2 注册和连接SQL
Server 2012服务器
54
2.4.3 启动和关闭SQL
Server 2012服务器
57
2.4.4
SQL Server 2012的常用工具 58
练习题
67
第3章 数据库的基本操作 68
3.1 SQL Server数据库的基本知识和概念 68
3.1.1
SQL Server的数据库对象
68
3.1.2
SQL Server的系统数据库
69
3.1.3 数据库的组成
70
3.1.4 数据库文件组
70
3.1.5 数据库的存储空间分配
72
3.2 创建数据库 73
3.2.1 使用对象资源管理器创建数据库
73
3.2.2 使用T-SQL语句创建数据库
78
3.3 查看和设置数据库信息 82
3.3.1 使用SQL
Server对象资源管理器查看数据库信息
82
3.3.2 使用T-SQL语句查看数据库的信息
82
3.4 打开数据库 83
3.5 修改数据库 84
3.5.1 增加数据库的容量
84
3.5.2 缩减数据库容量
89
3.5.3 创建和更改文件组
94
3.5.4 增加或删除数据库文件
95
3.5.5 更改数据库名称
99
3.6 分离数据库 100
3.7 附加数据库 101
3.8 删除数据库 103
3.9 应用举例 104
3.9.1 创建计算机计费数据库
104
3.9.2 创建选课管理数据库
104
练习题
106
第4章 表的基本操作 108
4.1 SQL Server表概述 108
4.1.1
SQL Server表的概念
108
4.1.2
SQL Server 2012数据类型 109
4.2 数据库中表的创建 112
4.2.1 使用对象资源管理器创建表
112
4.2.2 使用T-SQL语句创建表
115
4.3 修改表结构 118
4.3.1 使用对象资源管理器修改表结构
118
4.3.2 使用T-SQL语句修改表结构
119
4.4 删除表 120
4.4.1 使用对象资源管理器删除表
121
4.4.2 使用DROP
TABLE语句删除表
121
4.5 添加数据 122
4.5.1 使用对象资源管理器向表中添加数据
122
4.5.2 使用INSERT语句向表中添加数据
123
4.6 查看表 124
4.6.1 查看表结构
124
4.6.2 查看表中的数据
125
4.7 应用举例 126
4.7.1 学生选课管理信息系统的各表定义及创建
126
4.7.2 计算机计费系统的各表定义及创建
130
练习题
131
第5章 数据的基本操作 132
5.1 关系运算 132
5.1.1 关系数据结构的形式化定义
133
5.1.2 关系代数
134
5.1.3 关系代数的等价变换规则
142
5.1.4 关系代数表达式应用实例
142
5.2 单表查询 144
5.2.1 完整的SELECT语句的基本语法格式
144
5.2.2 选择表中的若干列
145
5.2.3 选择表中的若干记录
147
5.2.4 对查询的结果排序
156
5.2.5 对数据进行统计
158
5.2.6 用查询结果生成新表
161
5.2.7 集合查询
162
5.3 连接查询 165
5.3.1 交叉连接查询
165
5.3.2 等值与非等值连接查询
166
5.3.3 自身连接查询
168
5.3.4 外连接查询
169
5.3.5 复合连接条件查询
171
5.4 子查询 173
5.4.1 带有IN谓词的子查询
173
5.4.2 带有比较运算符的子查询
175
5.4.3 带有ANY或ALL谓词的子查询
178
5.4.4 带有EXISTS谓词的子查询
180
5.5 数据的添加、修改和删除 183
5.5.1 数据的添加
184
5.5.2 数据的修改
191
5.5.3 数据的删除
193
5.6 应用举例 194
练习题
197
第6章 索引及视图 200
6.1 索引的基础知识 200
6.1.1 数据存储
200
6.1.2 索引
200
6.2 索引的分类 201
6.2.1 聚集索引
201
6.2.2 非聚集索引
202
6.2.3 聚集和非聚集索引的性能比较
203
6.2.4 使用索引的原则
203
6.3 索引的操作 204
6.3.1 创建索引
204
6.3.2 查询索引信息
208
6.3.3 重命名索引
209
6.3.4 删除索引
209
6.4 索引的分析与维护 210
6.4.1 索引的分析
210
6.4.2 索引的维护
212
6.5 索引应用举例 214
6.6 视图综述 214
6.6.1 视图的基本概念
215
6.6.2 视图的作用
216
6.7 视图的操作 216
6.7.1 创建视图
217
6.7.2 修改视图
221
6.7.3 重命名视图
222
6.7.4 使用视图
223
6.7.5 删除视图
225
6.8 视图定义信息查询 227
6.8.1 使用对象资源管理器
227
6.8.2 通过执行系统存储过程查看视图的定义信息
228
6.9 加密视图 228
6.10 用视图加强数据安全性 229
6.11 视图应用举例 230
练习题
231
第7章 数据完整性 232
7.1 数据完整性的概念 232
7.2 约束的类型 233
7.3 约束的创建 234
7.3.1 创建主键约束
234
7.3.2 创建唯一约束
238
7.3.3 创建检查约束
239
7.3.4 创建默认约束
241
7.3.5 创建外键约束
243
7.4 查看约束的定义 245
7.5 删除约束 246
7.6 使用规则 246
7.7 使用默认 248
7.8 数据完整性强制选择方法 249
7.9 应用举例 250
练习题
251
第8章 SQL Server函数 252
8.1 内置函数 252
8.1.1 聚合函数
252
8.1.2 配置函数
255
8.1.3 日期和时间函数
256
8.1.4 数学函数
258
8.1.5 元数据函数
259
8.1.6 字符串函数
259
8.1.7 系统函数
262
8.1.8 排名函数
263
8.1.9 其他新增函数
264
8.2 用户定义函数 265
8.3 标量函数 267
8.4 表值函数 270
8.5 应用举例 274
练习题
275
第9章 SQL Server程序设计 277
9.1 程序中的批处理、脚本、注释
277
9.1.1 批处理
277
9.1.2 脚本
278
9.1.3 注释
279
9.2 程序中的事务 279
9.2.1 事务概述
280
9.2.2 事务处理语句
280
9.2.3 分布式事务
283
9.2.4 锁定
283
9.3 SQL Server变量 284
9.3.1 全局变量
284
9.3.2 局部变量
286
9.4 SQL语言流程控制 289
9.4.1
BEGIN…END语句块
289
9.4.2 IF…ELSE语句
289
9.4.3
CASE结构
290
9.4.4
WAITFOR语句
292
9.4.5
PRINT语句
293
9.4.6
WHILE语句
294
9.5 应用举例 295
练习题
297
第10章 存储过程与触发器 298
10.1 存储过程综述 298
10.1.1 存储过程的概念 298
10.1.2 存储过程的类型 298
10.1.3 创建、执行、修改、删除简单存储过程
299
10.1.4 创建和执行含参数的存储过程
305
10.1.5 存储过程的重新编译 305
10.1.6 系统存储过程与扩展存储过程
306
10.1.7 案例中的存储过程 309
10.2 触发器 311
10.2.1 触发器的概念 311
10.2.2 触发器的优点 311
10.2.3 触发器的类型 312
10.2.4 DML触发器 313
10.2.5 DDL触发器 328
10.2.6 案例中的触发器 329
练习题
331
第11章 SQL Server 2012安全管理 333
11.1 SQL Server 2012安全的相关概念 333
11.1.1 登录验证 333
11.1.2 角色 334
11.1.3 许可权限 335
11.2 服务器的安全性管理 335
11.2.1 查看登录账号 335
11.2.2 创建一个登录账号 336
11.2.3 更改、删除登录账号属性 338
11.2.4 禁止登录账号 338
11.2.5 删除登录账号 339
11.3 数据库安全性管理 340
11.3.1 数据库用户 340
11.3.2 数据库角色 341
11.3.3 管理权限 344
11.4 数据备份与还原 345
11.4.1 备份和还原的基本概念 345
11.4.2 数据备份的类型 346
11.4.3 还原模式 347
11.5 备份与还原操作 348
11.5.1 数据库的备份 348
11.5.2 数据库的还原 350
11.6 备份与还原计划 352
11.7 案例中的安全 353
11.8 案例中的备份和还原操作 357
11.9 数据导出与导入 363
练习题
367
第12章 数据库与开发工具的协同使用
369
12.1 常用的数据库连接方法 369
12.1.1 ODBC 369
12.1.2 OLE DB 371
12.1.3 ADO 371
12.2 在Visual Basic中的数据库开发
373
12.2.1 Visual Basic简介 373
12.2.2 在VB中使用ADO数据控件连接数据库
373
12.3 在Delphi或C
Builder中的数据库开发
376
12.3.1 Delphi与C Builder简介
376
12.3.2 C Builder提供的SQL Server访问机制
376
12.4 ASP与SQL Server 2012的协同运用
382
12.4.1 ASP运行环境的建立 382
12.4.2 在ASP中连接SQL
Server 2012数据库
383
12.4.3 ASP与SQL Server 2012数据库协同开发程序的方式
385
12.5 案例中的程序 386
12.5.1 学生信息管理 386
12.5.2 教师信息管理 389
12.5.3 学生信息查询 391
练习题
393
附录 实验指导 394
参考文献
407
数据库技术是20世纪60年代开始兴起的一门综合性的数据管理技术,也是信息管理中的一项非常重要的技术。进入20世纪90年代后,随着计算机及计算机网络的普及,网络数据库得到了日益广泛的应用。 本书具有以下特色: (1)理论与实践相结合。本书既介绍数据库的基本理论知识,又有取舍地基于 Windows 7操作系统介绍SQL Server 2012数据库中文版的基本操作及应用。 (2)以实例为主线。结合“选课管理信息系统”和“计算机计费系统”数据库案例,通过精心组织和系统编排,使学生通过案例学会数据库设计,使教学更具有针对性。 (3)本书讲解力求准确、简练,强调知识的层次性和技能培养的渐进性,例题和习题设计丰富实用,注重对学生的SQL Server数据库管理与开发技能的培养。 (4)在内容安排上遵循“循序渐进”与“难点分解”的原则,合理安排各章节内容。 全书共分12章,第1章由申时凯、韩红帮、肖红编写,第2章由邱莎、张志红编写,第3章由李海雁、黄吉花编写,第4章由申时凯、张大卫、佘玉梅编写,第5章由王付艳、申浩如编写,第6章由王武、李凯佳编写,第7章由马宏编写,第8章由段玻编写,第9章由申时凯、邱莎、佘玉梅编写,第10章由邱莎、王玉见编写,第11章和第12章由方刚编写,附录由邱莎、申时凯、何英、李冬萍编写,配套电子教案由上述老师共同制作。申时凯、邱莎、王付艳、方刚任主编,负责全书的策划和修改定稿工作;王武、王玉见、段玻、韩红帮任副主编。 本书得到云南省普通高等学校“十二五”规划教材、云南省科技计划项目(NO.2011FZ176)、昆明市物联网应用技术科技创新团队、昆明学院物联网应用技术科研创新团队(NO.2015CXTD04)、昆明学院应用型人才培养改革创新项目——应用型本科计算机类专业实践教学基地的资助。在本书的编写过程中,得到了日本函馆未来大学姜晓鸿教授的关心和指导,很多老师对本书的组织和协调做了大量工作,不少兄弟院校的老师对本书提出了宝贵的意见和建议。在此对他们深表谢意。 由于编者水平有限,书中不足之处在所难免,敬请广大读者批评指正。 编 者 2017年12月于昆明
图5-1 数据库表结构图5.1 关 系 运 算 1.2节介绍了关系数据库的相关概念,关系数据库应用数学方法来处理数据库中的数据,有的人把该处理过程称为关系操作,更多的人则称为关系运算。关系运算是关系数据模型的理论基础,由高度抽象的数学语言来表达,这些语言与具体的数据库管理系统中实现的实际语言并不完全相同,但它们能用于评估实际系统中查询语言的能力高低。关系运算包含关系代数和关系演算两个部分,关系演算以离散数学中的谓词演算为基础,此处限于篇幅,重点讨论关系数据结构的形式化定义和关系代数两个基本内容。5.1.1 关系数据结构的形式化定义 关系模型的数据结构非常单一,就是关系,它由关系数据结构、关系操作集合和关系完整性约束三部分组成。 关系模型中常用的关系操作有查询(Query)、插入(Insert)、删除(Delete)、修改(Update)操作。查询操作又可分为选择(Select)、投影(Project)、连接(Join)、除(Divide)、并(Union)、交(Intersection)、差(Except)和笛卡儿积(Cartesian Product)等。 关系模型的完整性规则是对关系的某种约束条件。有三类完整性约束:实体完整性(Entity Integrity)、参照完整性(Referential Integrity)和用户定义的完整性(User-defined Integrity),将在第7章详细介绍。 如何理解关系?从逻辑上看可以把关系理解为一张二维表,表是用来保持数据库所要描述数据的逻辑数据结构,而非物理结构。下面用集合代数来定义二维表的关系。 定义1 域(Domain)是一组具有相同数据类型的值的集合。 例如,学生性别域是{男,女},学生百分制成绩的域是0~100的整数集合。 定义2 给定一组域D1,D2,…,Dn,则D1,D2,…,Dn的笛卡儿积定义为: 其中,每一个元素(d1,d2,…,dn)称为一个n元组(n-tuple),简称元组(Tuple),元素中每一个值di称为一个分量(Component)。例如,给出两个域,学生姓名域D1={张斌,周红瑜}和专业名称域D2={软件工程,信息管理,经济管理},则D1和D2的笛卡儿积为:{(张斌,软件工程),(张斌,信息管理),(张斌,经济管理),(周红瑜,软件工程), (周红瑜,信息管理),(周红瑜,经济管理)}表示学生姓名和专业名的所有可能组合。其中(张斌,软件工程)、(周红瑜,信息管理)等都是元组。张斌、周红瑜、软件工程、经济管理等都是分量。若Di(i=1,2,…,n)为有限集,其基数(Cardinal number)为mi(i=1,2,…,n)(基数是一个表中除属性行外的行的总数),则D1×D2×…×Dn的基数为: 上例中D1×D2一共有2×3=6个元组。 定义3 关系(Relation)。 D1×D2×…×Dn的子集叫作在域D1,D2,…,Dn上的关系,表示为R(D1,D2,…,Dn)。R表示关系的名字,n为关系的目或度(Degree),当n=1时,称该关系为单元关系或一元关系(Unary relation);当n=2时,称该关系为二元关系(Binary relation)。关系是笛卡儿积的有限子集,关系也是二维表,表的每行对应一个元组,每列对应一个域。由于域可以相同,如学生学号和身份证号有可能都为整数域,为了加以区分,必须为每列起一个名字,称为属性(Attribute)。n目关系必有n个属性。图5-2给出了用表描述关系的一般格式。 值得注意的是,基本关系具有以下4个特点: (1)关系(表)可以看成是由行和列交叉组成的二维表。同列具有相同的域,即每一列中的各个分量属于同一数据类型。不同的列可以有相同的域。 (2)表中任意两行(元组)不能完全相同。
图5-2 用表描述关系的一般格式 (3)行的顺序可以任意交换,列的顺序也可任意交换。 (4)各分量必须是原子值,即每一个分量不可再分解,这是由于关系模式要求关系必须满足一定的规范条件,这也是把规范化的关系称为范式的原因。通常数据库中不允许出现非原子分量,即数据表中含有可再分解的“表”,俗称“表中表”现象。5.1.2 关系代数 关系代数是允许从给定关系集合中构造新关系的运算符全集,它是一种抽象的查询语言,是关系数据操纵语言(DML)的一种传统表达方式。关系代数以集合代数为基础发展而来,以关系为运算对象,其运算结果仍为关系。关系代数用到的运算符称为关系运算符,包括传统集合运算符、针对数据库表进行操作的专用运算符以及算术比较和逻辑运算符,如表5-1所示。对关系的每种运算都解决面向数据库的一个询问,用数据库的术语简称为查询或检索。表5-1 关系代数运算符集合运算符专用关系运算符符 号含 义符 号含 义符 号含 义
并(Union)
选择(Selection)
投影(Projection)
交(Intersection)
F连接(Formula Join)
θ连接(Theta Join)—差(Difference)
等值连接(Equijoin)
自然连接(Natural Join)
广义笛卡儿积(ECP)
半连接(Semijoin)
除(Division)逻辑运算符比较运算符符 号含 义符 号含 义符 号含 义
逻辑非(NOT)>大于逻辑与(AND)≥大于或等于≤小于或等于
逻辑或(OR)=等于<>不等于 1.传统集合运算 传统集合运算把关系看成元组的集合,其运算从“水平”方向即行的角度来进行。设关系R和关系S具有相同的度n(即两个关系都有n个属性),且相应属性取自同一个域,记t为元组变量,定义并、交、差运算如下: 1)并 ,并运算是将两个关系中的所有元组构成一个新关系,结果应该消除重复的元组。 【例5.1】 表5-2(a)和表5-2(b)所示的两个关系:开设C程序设计课程教师情况和Java程序设计课程教师情况,执行并操作得到如表5-2(c) 所示结果,即开设计算机程序设计课程的教师情况。表5-2(a) C_teachers工 号姓 名性 别所 属 系 部T107何英女 计算机系T207王宁男 计算机系T306李杰男 数学系表5-2(b) Java_teachers工 号姓 名性 别所 属 系 部T211 张学杰男 信息工程系T107 何英女 计算机系表5-2(c) C_teachers ∪ Java_teachers工 号姓 名性 别所 属 系 部T107 何英女 计算机系T207 王宁男 计算机系T306 李杰男 数学系T211 张学杰男 信息工程系 2)交 ,交运算得到的关系由既属于R又属于S的元组组成。上例中的,得到如表5-3所示结果,即同时开设两门课程的教师情况。表5-3 C_teachers ∩ Java_teachers工 号姓 名性 别所 属 系 部T107何英女计算机系 3)差 ,差运算得到的关系由属于R而不属于S的所有元组组成。在差运算中顺序非常重要,,上例中表示只开设了C程序设计的教师情况,而则表示只开设了Java程序设计的教师情况,分别如表5-4(a)、(b)所示。表5-4(a) C_teachers – Java_teachers工 号姓 名性 别所 属 系 部T207王宁男 计算机系T306李杰男 数学系表5-4(b) Java_teachers – C_teachers工 号姓 名性 别所 属 系 部T211张学杰男信息工程系 4)广义笛卡儿积 在5.1.1节中已给出了笛卡儿积的定义,记作: 笛卡儿积运算得到的关系,其度是R和S的度之和,基数是R和S的基数之积。值得注意的是,笛卡儿积运算得到的结果可能没有任何意义,而且计算代价较大。有时也把笛卡儿积运算叫作交叉连接或非限制连接。 【例5.2】 以“学生”表(见表5-5)和“专业”表(见表5-6)为例说明笛卡儿积的运算过程,两表产生的结果集如表5-7所示。表5-5 “学生”表(Student)学 号(SNO)姓 名(Name)性 别(Sex)系 部 代 码(Dept_NO)专 业 代 码(Spec_NO)010101001001 张斌男010101010102002001 周红瑜女010102010201001001 贾凌云男020201010202002001 向雪林女020202表5-6 “专业”表(Specialty)专 业 代 码(Spec_NO)专 业 名 称(Spec)系 部 代 码(Dept_NO)0101 软件工程010102 信息管理010201 经济管理020202 会计02表5-7 交叉连接的结果表学 号(SNO)姓 名(Name)性 别(Sex)系 部 代 码(Dept_NO)专 业 代 码(Spec_NO)专 业 代 码*(Sp_NO)专 业 名 称(Spec)系 部 代 码*(De_NO)010101001001张斌男0101010101软件工程01010102002001周红瑜女0101020101软件工程01010201001001贾凌云男0202010101软件工程01010202002001向雪林女0202020101软件工程01010101001001张斌男0101010102信息管理01010102002001周红瑜女0101020102信息管理01010201001001贾凌云男0202010102信息管理01010202002001向雪林女0202020102信息管理01010101001001张斌男0101010201经济管理02010102002001周红瑜女0101020201经济管理02010201001001贾凌云男0202010201经济管理02010202002001向雪林女0202020201经济管理02010101001001张斌男0101010202会计02010102002001周红瑜女0101020202会计02010201001001贾凌云男0202010202会计02010202002001向雪林女0202020202会计02 以上执行过程是:把“学生”表(共有5个属性列)中的每一条记录取出(共有4条记录),与“专业”表(共有3个属性列)中的第一条记录连接,形成如表5-7所示的前4条记录;同样地,再取出“学生”表中的每一条记录,与“专业”表中的第二条至第四条记录分别连接,从而形成后12条记录,一共形成了4(来自“学生”表)×4(来自“专业”表)=16条记录,即16个元组,同时,该笛卡儿积有8个属性列=5(来自“学生”表) 3(来自“专业”表)。在表5-7中加“*”的“专业代码”和“系部代码”列是为了区别来自表5-5和表5-6具有相同名称的列。 关系也满足集合运算的若干定律,设关系R、S和Q具有相同的度n,且相应属性取自同一个域,则有: (1)结合律。 (2)交换律。; (3)分配律。 (4)吸收律。; (5)关系的交可以用差来表示。 2.专用关系运算 专用关系运算包括选择、投影、连接、除等。 1)选择 ,在关系R中选择符合条件F的元组,也就是从关系R中选取使逻辑表达式F为真的元组,F由逻辑运算符连接各种算术表达式组成。选择运算是根据某些条件对关系做水平分割,目的是检索一个特定的列中一个给定值的元组或元组集合的所有可能信息。例如,表5-5、表5-6分别列出了学生和专业情况,现在要查询经济管理专业(已知专业代码为0201)的全体学生,用关系代数表示为或,其中下标5是Spec_NO的属性序号。结果如表5-8所示。表5-8 经济管理专业学生的查询结果(选择运算)学 号(SNO)姓 名(Name)性 别(Sex)系 部 代 码(Dept_NO)专 业 代 码(Spec_NO)010201001001贾凌云男020201 若要列出所有女同学的基本情况则表示为或,其中下标3是Sex的属性序号。查询结果如表5-9所示。表5-9 全体女生的查询结果(选择运算)学 号(SNO)姓 名(Name)性 别(Sex)系 部 代 码(Dept_NO)专 业 代 码(Spec_NO)010102002001周红瑜女010102010202002001向雪林女020202 2)投影 ,其中X={A1,A2,…,Ak}是关系R属性的子集,它是先删除在X中没有指明的列,然后删除一些重复的元组(因为取消了某些属性列后,就可能出现重复行),而得到的一个新的关系,即运算结果中的一个元组j的记录是从关系R的元组j选择记录统计tj(A1),tj(A2),…,tj(Ak)而形成的。投影运算是对一个关系做垂直分割,目的是研究某个特定列或者某几个列存在的不同值。例如在表5-5中查询学生学号和姓名,用关系代数表示为或,其中下标1和2分别是SNO和Name的属性序号。查询结果如表5-10所示。表5-10 全体学生的学号、姓名的查询结果(投影运算)学 号(SNO)姓 名(Name)010101001001 张斌010102002001 周红瑜010201001001 贾凌云010202002001 向雪林 若要列出所有系部代码,则应查询表5-6,表示为或,其中下标3是Dept_NO的属性序号。结果如表5-11所示。表5-11 系部代码的查询结果(投影运算)系 部 代 码(Dept_NO)0102 3)连接 连接运算将两个关系连在一起,形成一个新的关系。通常连接也称为θ连接,它是从两个关系的笛卡儿积中选取属性值满足某一条件的元组,即从R和S的广义笛卡儿积R×S中选取(R关系)在A属性上的值与(S关系)在B属性上的值满足比较关系θ的元组,记为: 其中,A和B分别为R和S上度数相等且可比的属性组,θ为比较运算符。θ连接一般不直接被关系数据库厂商支持,它可以被模拟成选择和投影运算。 当θ为“=”时,称该连接为等值连接,它是从R和S的广义笛卡儿积R×S中选取A、B属性值相等的元组,记为: 当要求等值连接得到的结果中去掉重复的属性列时,就产生了一种特殊的等值连接,叫自然连接。自然连接继承了“等值连接两个关系中进行比较的分量必须是相同的属性组”这个规则。一般的连接运算是从行的角度进行,而自然连接还需要消除重复列,同时从行和列的角度进行运算。自然连接记为: 此外,还有一种F连接,从R和S的广义笛卡儿积R×S中选取属性间满足某一公式F的元组,F是形如F1∧F2∧…∧Fi∧…∧Fn的公式,每个Fi等价于的形式。图5-3描述了各种连接的层次关系。
图5-3 各种连接的层次关系 【例5.3】 表5-12~表5-14分别是“学生成绩”表、“成绩等级”表和“选课情况”表。表5-12 “学生成绩”表(SCG)学 号(SNO)课 程 号(CNO)成 绩(Grade)S001Math0188S002Math0290S201Math0178S202Eng1869S301Math0283S302Math0164表5-13 “成绩等级”表(GL)成 绩 边 界(G)等 级(Level)90A80B表5-14 “选课情况”表(CS)课 程 号(CNO)课 程 名 称(Cname)选课学生学号(SNO)选课学生姓名(Sname)Math01高等数学S001 张斌Math02离散数学S002 周红瑜Math01高等数学S201 贾凌云Math02离散数学S301 黄丽Math01高等数学S302 杨素梅 首先,要求列出获得成绩等级的学生情况(包括其成绩等级、所修课程等信息)。用关系代数表示为,这是一个θ连接运算,等价于执行操作。结果如表5-15所示。表5-15 获得成绩等级的学生情况(SCGL)学 号(SNO)课 程 号(CNO)成 绩(Grade)成绩边界(G)等 级(Level)S001Math018880BS002Math029090AS301Math028380B 根据表5-15,列出与表5-14中相匹配的学生情况(包括课程名称、学生姓名等信息)。用关系代数表示为,这是一个自然连接运算,等价于执行
或
结果如表5-16所示。表5-16 获得成绩等级的学生详细情况学 号(SNO)学生姓名(Sname)课 程 号(CNO)课程名称(Cname)成 绩(Grade)成绩边界(G)等 级(Level)S001 张斌Math01高等数学8880BS002 周红瑜Math02离散数学9090AS301 黄丽Math02离散数学8380B 4)除 在介绍除运算之前先给出像集的定义。关系R(X,Z)中X和Z为属性组,当时,在R中的像集定义为: 表示R中属性组X上值为的诸元组在属性组Z上分量的集合。例如表5-17所示的关系R,其中属性列A可以取三个值,则有:a1的像集为,a2的像集为,a3的像集为。表5-17 关系RABCa1b1c5a2b2c1a1b4c5a3b3c4a2b6c2 由此给出除运算定义:关系R(X,Y)和S(Y,Z),其中X、Y、Z为属性组。R中的Y与S中的Y必须出自同一个域,则,新关系Q是R满足下列条件的元组在X属性组上的投影,即元组在X上分量值x的像集Yx包含S在Y上投影的集合。记作:,其中Yx是x在R上的像集,x=tr[X]。除运算的定义很复杂,用来回答这样的问题:一个表的哪些元组包含在另一个表的某特定列的所有值,其具体计算过程是: (1) (2) (3) (4) 另给出关系S如表5-18所示。表5-18 关系SUBCu1b1c5u2b4c5 显然,只有a1的像集包含了,因此,,如表5-19所示。表5-19 的结果 A a1 【例5.4】 给出“学生学习情况”表(见表5-20)和“主干课程成绩等级”表(见表5-21),查询主干课程成绩优秀(等级A)的学生情况(学号、姓名和专业)。表5-20 “学生学习情况”表(SCG)学号(SNO)学生姓名(Sname)专业名称(Spec)课程名称(Cname)成绩等级(Glevel)S001 张小斌 通信工程 计算机网络AS001 张小斌 通信工程 数理方程BS001 张小斌 通信工程 数据结构AS002 周念 计算机科学与技术 计算机网络AS002 周念 计算机科学与技术 数据结构AS301 黄丽丽 计算机科学与技术 数据结构AS201 贾云飞 电子信息工程 计算机网络BS201 贾云飞 电子信息工程 数理方程AS201 贾云飞 电子信息工程 数据结构A表5-21 “主干课程成绩等级”表(CL)课程名称(Cname)等级(Level) 数据结构A 计算机网络A 本例是一个典型的除运算例子,即,显然,只有“张小斌”和“周念”两人满足修读主干课程及相应成绩等级的条件,结果如表5-22所示。表5-22 主干课程成绩优秀的学生情况()学 号(SNO)学 生 姓 名(Sname)专 业 名 称(Spec)S001 张小斌 通信工程S002 周念 计算机科学5.1.3 关系代数的等价变换规则 关系代数表达式的满足一些等价变换规则。设E1和E2是关系代数表达式,F是连接条件,L是属性集,则有: (1)连接交换律、笛卡儿积交换律:,,。 (2)投影串联。,其中L1,L2,…,Ln为属性集,且。 (3)选择串联。,其中,则又有选择的交换律:。 (4)选择对集合并的分配律:,E1和E2具有相同的属性名,或E1和E2表达的关系的属性有对应性。 (5)选择对集合差的分配律:,E1和E2的属性有对 应性。 (6)投影对集合并的分配律:,E1和E2的属性有对 应性。 (7)投影对笛卡儿积的分配律:,L1是E1的属性集,L2是E2的属性集。 (8)选择和投影操作的交换律:,F只涉及L中的属性,若F涉及非L中的属性L’,那么就有。 (9)选择对自然连接的分配律:,F只涉及E1和E2的公共属性。 (10)选择与连接操作的结合律:,。 其余规则请读者总结,此处不再详述。5.1.4 关系代数表达式应用实例 并、差、笛卡儿积、投影和选择是关系代数最基本的操作,构成了关系运算的最小完备集。已经证明关系代数、安全的关系演算(对关系演算施加了安全约束条件)在关系的表达和操作能力上是等价的。我们可以用关系代数表达式表示各种数据查询操作,其执行的一般过程如图5-4所示。需要注意的是,当查询涉及否定或全部、包含值时,下述流程就不能完全胜任了,要用到差运算或除运算。
图5-4 关系代数表达式的一般执行流程 【例5.5】 设教学管理数据库中有三个关系,带下画线的属性为主键: 学生关系Student(SNO,Sname,Age,Sex,Sdept) 课程关系Course(CNO,Cname,Cdept) 学习关系SC(SNO,CNO,Grade) (1)查询电子工程系全体学生的学号、姓名和性别。 属于单表查询,关系代数表达式为。 (2)查询学习课程号为Math02的学生学号与姓名。 属于两表连接查询,关系代数表达式为。 (3)查询选修课程名为“离散数学”的学生学号与姓名。 属于三表连接查询,关系代数表达式为。 (4)至少选修课程号为Math01和Math02的学生学号。 涉及多条件查询,关系代数表达式为,其中,SC1和SC2是关系SC的别名,这里表示关系SC自身进行笛卡儿积运算,而选择表达式则表示同一个学生既选修了Math01课程又选修了Math02课程。 (5)查询没有选修Math02课程的学生学号与姓名。 这里用全体学生的学号与姓名集合同选修了Math02课程的学生学号与姓名集合进行差运算。关系代数表达式为。 (6)查询选修了所有课程(号)的学生学号。 先求学生选课情况,再求开设的全部课程,选修了全部课程的学生学号用除运算表示为。 除了能够正确写出符合查询要求的关系代数表达式外,还应该考虑表达式的优化问题,即系统应该以什么样的操作顺序,才能兼顾时间、空间和效率三者。有一些优化策略,比如,在表达式中尽可能早地执行选择运算;把笛卡儿积和其后的选择操作合并成F连接运算;应对在一个表达式中多次出现的某个子表达式预处理,即预先计算好结果保存起来等等。例如上题中的,可以利用选择对自然连接的分配律,把选择运算移至关系Course前面,得到: 在每个操作后,应做投影运算,挑选完后操作中需要的属性,去掉不用的属性值,减少中间的数据量,最终得到一个比较优化的表达式:
5.2 单 表 查 询 数据库存在的意义在于将数据组织在一起,以方便查询。“查询”的含义就是用来描述从数据库中获取数据和操纵数据的过程。本节主要涉及单个数据表中信息的查询问题。 SQL语言中最主要、最核心的部分是查询功能。查询语言用来对已经存在于数据库的数据按照特定的组合、条件表达式或者一定次序进行检索。其基本格式是由SELECT子句、FROM子句和WHERE子句组成的SQL查询语句: SELECT FROM WHERE 也就是说,SELECT指定了要查看的列(字段),FROM 指定这些数据的来源(表或者视图),WHERE则指定了要查询哪些记录。 注意:在T-SQL语言中,SELECT子句除了进行查询外,其他的很多功能也都离不开SELECT子句,例如,创建视图是利用查询语句来完成的;插入数据时,在很多情况下是从另外一个表或者多个表中选择符合条件的数据。所以查询语句是掌握T-SQL语言的关键。 5.2.1 完整的SELECT语句的基本语法格式 虽然SELECT语句的完整语法较复杂,但是其主要的语法格式可归纳如下: SELECT select_list [INTO new_table_name] FROM table_list[WHERE search_conditions] [GROUP BY group_by_expression][HAVING search_conditions] [ORDER BY order_expression [ASC|DESC]] 其中,带有中括号的子句是可选择的,大写的单词表示SQL的关键字,而小写的单词或词组表示表或视图名称或给定的条件。以上语法格式的详细说明如下:* SELECT select_list描述结果集的列,它是一个由逗号分隔的表达式列表。每个表达式通常是从中获取数据的源表或视图的列的引用,但也可能是其他表达式,例如常量或T-SQL函数。在选择列表中使用“*”表达式指定返回源表中的所有列。* [INTO new_table_name]用于指定使用结果集来创建一个新表,new_table_name是新表的名称。* FROM table_list包含从中检索到结果集数据来创建的表的列表,也就是结果集数据来源于哪些表或视图,FROM子句还可包含连接的定义。* [WHERE search_conditions]中的WHERE子句是一个筛选,它定义了源表中的行要满足SELECT语句的要求所必须达到的条件。只有符合条件的行才向结果集提供数据,不符合条件的行中的数据不会被使用。* GROUP BY group_by_expression中GROUP BY子句根据group_by_expression列中的值将结果集分成组。* HAVING search_conditions中HAVING子句是应用于结果集的附加筛选。从逻辑上讲,HAVING子句从中间结果集对行进行筛选,这些中间结果集是用SELECT语句中的FROM、WHERE或GROUP BY子句创建的。HAVING子句通常与GROUP BY子句一起使用,尽管HAVING子句前面不必有GROUP BY子句。* ORDER BY order_expression [ASC | DESC]中ORDER BY子句定义结果集中的行排列的顺序。order_expression指定组成排序列表的结果集的列。ASC和DESC关键字用于指定行是按升序还是按降序排序。5.2.2 选择表中的若干列 选择表中的全部列或部分列就是表的投影运算。这种运算可以通过SELECT子句给出的字段列表来实现。字段列表中的列可以是表中的列,也可以是表达式列。所谓表达式列,就是多个列运算后产生的列或者是利用函数计算后所得的列。 1.输出表中的所有列 将表中的所有字段都在“结果”窗格中列出来,可以有两种方法:一种是将所有的字段名在SELECT关键字后列出来;另一种是在SELECT语句后使用一个“*”。 【例5.6】 查询“学生”表中全体学生的记录。 代码如下: USE student GOSELECT *FROM 学生GO 在查询编辑器中输入并执行上述代码,将返回学生表中的全部列,如图5-5所示。 2.输出表中部分列 如果在“结果”窗格中列出表中的部分列,可以将要显示的字段名在SELECT关键字后依次列出来,列名与列名之间用英文逗号隔开,字段的顺序可以根据需要来指定。 【例5.7】 查询全体教师的教师编号、姓名和职称信息。
图5-5 查询“学生”表的全部字段 代码如下: USE studentGOSELECT 教师编号,姓名,职称FROM 教师GO 在查询编辑器中输入并执行上述代码,在“结果”窗格中将只有“教师编号”“姓名”和“职称”三个字段,如图5-6所示。
图5-6 查询全体教师的编号、姓名和职称 3.为“查询结果”窗格内的列指定别名 有时,“查询结果”窗格中的列不是表中现成的列,而是通过表中的一个或多个列计算出来的,这时,需要为这个计算列指定一个列名,同时该表达式将显示在字段列表中。格式如下: SELCET 表达式 AS 列别名FROM 数据源 【例5.8】 查询“教师”表中全体教师的姓名及年龄。 代码如下: USE studentGOSELECT 姓名,YEAR(GETDATE())-YEAR(出生日期) AS 年龄FROM 教师GO 其中,“YEAR(GETDATE())-YEAR(出生日期)”是表达式,其含义是取得系统当前日期中的年份减去“出生日期”字段中的年份,就是教师的当前年龄。“年龄”是表达式别名。将上述代码在查询编辑器中输入并执行,返回结果如图5-7所示。
图5-7 带有别名的查询5.2.3 选择表中的若干记录 选择表中的若干记录这就是表的选择运算。这种运算可以通过增加一些谓词(例如WHERE子句)等来实现。 1.消除取值重复的行 两个本来并不相同的记录,当投影到指定的某些列上后,可能变成相同的行。如果要去掉结果集中重复的行,可以在字段列表前面加上DISTINCT关键字。 【例5.9】 查询选修了课程的学生学号。 代码如下: USE studentGOSELECT 学号FROM 课程注册GO 上述代码执行结果如图5-8所示,选课的学生号有重复,共有36条记录。下面的代码就去掉了重复的学号,仅有7条记录,执行结果如图5-9所示。 USE studentGOSELECT DISTINCT 学号FROM 课程注册GO 图5-8 未去掉重复学号的查询 2.限制返回行数 如果一个表中有上万条记录,而用户只想查看记录的样式和内容,这就没有必要显示全部的记录。如果要限制返回的行数,可以在字段列表之前使用TOP n关键字,则查询结果只显示表中前面的n条记录,如果在字段列表之前使用TOP n PERCENT关键字,则查询结果只显示前面n%条记录。
图5-9 去掉了重复学号的查询 【例5.10】 查询“课程注册”表中的前三条记录的信息。 代码如下: USE studentGOSELECT TOP 3 *FROM 课程注册GO 在查询编辑器中输入并执行上述代码,执行结果如图5-10所示。
图5-10 显示前三条记录 3.查询满足条件的元组 如果只希望得到表中满足特定条件的一些记录,可以在查询语句中使用WHERE子句。使用WHERE子句的条件如表5-23所示。表5-23 常用的查询条件查 询 条 件运 算 符含 义比较=、>、=、<=、!=、<>、!>; NOT 上述运算符比较大小确定范围BETWEEN…AND…、NOT BETWEEN…AND…判断值是否在范围内确定集合IN、NOT IN判断值是否为列表中的值字符匹配LIKE、NOT LIKE判断值是否与指定的字符通配格式相符空值IS NULL、NOT IS NULL判断值是否为空多重条件AND、OR、NOT用于多重条件判断 1)比较大小 比较运算符是比较两个表达式大小的运算符,各运算符的含义是=(等于)、>(大于)、=(大于或等于)、<=(小于或等于)、<>(不等于)、!=(不等于)、!(不大于)。逻辑运算符NOT可以与比较运算符同用,对条件求非。 【例5.11】 查询“课程注册”表成绩大于等于50分的记录。 代码如下: USE studentGOSELECT *FROM 课程注册WHERE 成绩>=50GO 将上述代码在查询编辑器中输入并执行,结果如图5-11所示。
图5-11 查询成绩大于等于50分的记录 2)确定范围 范围运算符BETWEEN…AND…和NOT BETWEEN…AND…可以查找属性值在(或不在)指定的范围内的记录。其中,BETWEEN后是范围的下限(即低值),AND后是范围的上限(即高值)。语法格式如下: 列表达式 [NOT] BETWEEN 起始值AND 终止值 【例5.12】 查询出生日期在1992—1995年的学生姓名、学号和出生日期。 代码如下: USE studentGOSELECT 姓名,学号,出生日期FROM 学生WHERE year(出生日期) BETWEEN 1992 AND 1995GO 上述代码的含义是:如果返回出生日期的年份大于等于1992且小于等于1995,则该记录会在“结果”窗格中显示。在查询编辑器中输入并执行上述代码,执行结果如图5-12所示。
图5-12 范围查找 3)确定集合 确定集合运算符IN和NOT IN可以用来查找属性值属于(或不属于)指定集合的记录,运算符的语法格式如下: 列表达式[NOT] IN(列值1,列值2,列值3,…) 【例5.13】 查询计算机系(系部代码是01)、经济管理系(系部代码是02)的班级名称与班级编号。 代码如下: USE studentGOSELECT 班级代码,班级名称FROM 班级WHERE 系部代码 IN(’01’,’02’)GO 将上述代码在查询编辑器中输入并执行,结果如图5-13所示。
图5-13 确定集合查询 4)字符匹配 在实际的应用中,用户有时候不能给出精确的查询条件。因此,经常需要根据一些不确定的信息来查询。T-SQL语言提供了字符匹配运算符LIKE进行字符串的匹配运算,实现这类模糊查询。其一般语法格式如下: [NOT] LIKE ” [ESCAPE ”] 其含义是查找指定的属性列值与“”相匹配的记录。“”可以是一个完整的字符串,也可以含有通配符“%”和“_”,其中通配符包括如下四种。 (1)%(百分号),代表任意长度的字符串(长度可以是0)的字符串。例如,a%b表示以a开头、以b结尾的任意长度的字符串。例如,acb、adxyzb、ab等都满足该匹配串。 (2)_(下画线),代表任意单个字符。例如,a_b表示以a开头,以b结尾的长度为3的任意字符串。如afb等。 (3)[]表示中括号里列出的任意一个字符。例如A[BCDE],表示第一个字符是A,第二个字符为B、C、D、E中的任意一个。也可以是字符范围,例如A[B-E]同A[BCDE]的含义相同。 (4)[^]表示不在中括号里列出的任意一个字符。 【例5.14】 查询“学生”表中姓“周”的学生的信息。 代码如下: USE studentGOSELECT *FROM 学生WHERE 姓名 LIKE ‘周%’GO 通配符字符串“’周%’”的含义是第一个汉字是“周”的字符串。将上述代码在查询编辑器中输入并执行,执行结果如图5-14所示。
图5-14 模糊查询 如果用户要查询的字符串本身就含有%或_,这时就需要使用“ESCAPE””短语对通配符进行转义了。 【例5.15】 有一门课程的名称是Photoshop CC_2014,查询它的课程号和课程名。 代码如下: USE studentGOINSERT INTO 课程 (课程号,课程名,学分)VALUES(‘0008′,’Photoshop CC_2014′,’4’)GOSELECT 课程号,课程名FROM 课程WHERE 课程名 LIKE ‘Photoshop CC/_2014’ ESCAPE ‘/’GO “ESCAPE’/’”短语表示“/”是换码字符,这样匹配串中紧跟在“/”之后的字符“_”不再具有通配符的含义,转义为普通的“_”字符。本例中的INSERT语句是向“课程”表插入一条新记录,以便完成后面的查找任务。INSERT语句将在后续章节中详细讲解。 将上述代码在查询编辑器中输入并执行,结果如图5-15所示。
图5-15 使用“ESCAPE””短语对通配符“_”进行转义 5)涉及空值的查询 一般情况下,表的每一列都有其存在的意义,但有时某些列可能暂时没有确定的值,这时用户可以不输入该列的值,那么这列的值为NULL。NULL与0或空格是不一样的。空值运算符IS NULL用来判断指定的列值是否为空。语法格式如下: 列表达式 [NOT] IS NULL 【例5.16】 查询“教师”表中备注字段为空的教师信息。 代码如下: USE studentGOSELECT *FROM 教师WHERE 备注 IS NULLGO 这里的IS运算符不能用“=”代替。将上述代码在查询编辑器中输入并执行,执行结果如图5-16所示。
图5-16 查询空值 6)多重条件查询 用户可以使用逻辑运算符AND、OR、NOT连接多个查询条件,实现多重条件查询。逻辑运算符使用格式如下: [NOT] 逻辑表达式 AND|OR [NOT] 逻辑表达式 【例5.17】 查询“课程注册”表中课程号为0001成绩在80~89分(不含89分)的学生的学号、成绩。 代码如下: USE studentGOSELECT 学号,成绩FROM 课程注册WHERE 课程号=’0001′ AND 成绩>=80 AND 成绩<89GO 将上述代码在查询编辑器中输入并执行,结果如图5-17所示。
图5-17 多重条件查询5.2.4 对查询的结果排序 可以使用ORDER BY子句对查询结果按照一个或多个属性列的升序(ASC)或降序(DESC)排列,默认为升序。如果不使用ORDER BY子句,则结果集按照记录在表中的顺序排列。ORDER BY子句的语法格式如下: ORDER BY {列名 [ASC|DESC]}[,…n] 当按多列排序时,先按前面的列排序,如果值相同再按后面的列排序。 【例5.18】 查询选修了0001号课程的学生的学号,并按成绩降序排列。 代码如下: USE studentGOSELECT 学号,成绩FROM 课程注册WHERE 课程号=’0001’ORDER BY 成绩 DESCGO 将上述代码在查询编辑器中输入并执行,结果如图5-18所示。 【例5.19】 查询全体学生信息,查询结果按所在班级代码降序排列,同一个班的按照学号升序排列。
图5-18 将查询结果降序排序 代码如下: USE studentGOSELECT *FROM 学生ORDER BY 班级代码 DESC,学号 ASCGO 将上述代码在查询编辑器中输入并执行,结果如图5-19所示。
图5-19 组合排序5.2.5 对数据进行统计 需要对结果集进行统计,例如求和、平均值、最大值、最小值、个数等,这些统计可以通过集合函数、COMPUTE子句、GROUP BY子句来实现。 1.使用集合函数 为了进一步方便用户,增强检索功能,SQL Server提供了许多集合函数,主要有: (1)COUNT( [ DISTINCT | ALL ] * )统计记录个数。 (2)COUNT( [ DISTINCT | ALL ] )统计一列中值的个数。 (3)SUM( [ DISTINCT | ALL ] )计算一列值的总和(此列必须是数值型)。 (4)AVG( [ DISTINCT | ALL ] )计算一列值的平均值(此列必须是数值型)。 (5)MAX( [ DISTINCT | ALL ] )求一列值中的最大值。 (6)MIN( [ DISTINCT | ALL ] )求一列值中的最小值。 在SELECT子句中,集合函数用来对结果集记录进行统计计算。DISTINCT是去掉指定列中的重复信息的意思,ALL是不取消重复,默认是ALL。 【例5.20】 查询“教师”表中的教师总数。 代码如下: USE studentGOSELECT COUNT(*) AS 教师总数FROM 教师GO 将上述代码在查询编辑器中输入并执行,结果如图5-20所示。
图5-20 统计记录总数 【例5.21】 查询“课程注册”表中学生的成绩平均分。 代码如下:USE studentGOSELECT AVG (成绩) AS 平均分FROM 课程注册GO 将上述代码在查询编辑器中输入并执行,结果如图5-21所示。
图5-21 求学生成绩的平均分 2.对结果进行分组 GROUP BY子句将查询结果集按某一列或多列值分组,分组列值相等的为一组,并对每一组进行统计。对查询结果集分组的目的是为了细化集合函数的作用对象。GROUP BY子句的语法格式为: GROUP BY列名 [HAVING筛选条件表达式] 其中:* “BY 列名”是按列名指定的字段进行分组,将该字段值相同的记录组成一组,对每一组记录进行汇总计算并生成一条记录。* “HAVING筛选条件表达式”表示对生成的组筛选后再对满足条件的组进行统计。 SELECT子句的列名必须是GROUP BY子句已有的列名或是计算列。 【例5.22】 查询“课程注册”表中课程选课人数4人以上的各个课程号和相应的选课人数。 代码如下: USE studentGOSELECT 课程号,COUNT(*) AS 选课人数FROM 课程注册GROUP BY 课程号HAVING COUNT(*)>=4GO 将上述代码在查询编辑器中输入并执行,结果如图5-22所示。 HAVING与WHERE子句的区别在于作用的对象不同。HAVING作用于组,选择满足条件的组;WHERE子句作用于表,选择满足条件的记录。
图5-22 分组统计 3.使用COMPUTE子句 COMPUTE子句对查询结果集中的所有记录进行汇总统计,并显示所有参加汇总记录的详细信息。使用语法格式如下: COMPUTE 集合函数 [BY 列名] 其中:* 集合函数,例如SUM()、AVG()、COUNT()等。* “BY列名”按指定“列名”字段进行分组计算,并显示被统计记录的详细信息。* BY选项必须与ORDER BY子句一起使用。 COMPUTE BY子句之前要使用ORDER BY子句,原因是必须先按分类字段排序之后才能使用COMPUTE BY子句进行分类汇总。COMPUTE BY与GROUP BY子句的区别在于:前者既显示统计记录又显示详细记录,后者仅显示分组统计的汇总记录。 注意:SQL Server 2012废弃了COMPUTE和COMPUTE BY功能,此处不再举例赘述。5.2.6 用查询结果生成新表 在实际的应用系统中,有时需要将查询结果保存成一个表,这个功能可以通过SELECT语句中的INTO子句实现。INTO子句语法格式如下: INTO 新表名 其中:* 新表名是被创建的新表,查询的结果集中的记录将添加到此表中。* 新表的字段由结果集中的字段列表决定。* 如果表名前加“#”则创建的表为临时表。* 用户必须拥有该数据库中建表的权限。* INTO子句不能与COMPUTE子句一起使用。 【例5.23】 创建“课程注册”表的一个副本。 代码如下: USE studentGOSELECT * INTO 课程注册副本FROM 课程注册GOSELECT *FROM 课程注册副本GO 将上述代码在查询编辑器中输入并执行,结果如图5-23所示。
图5-23 生成新表 【例5.24】 创建一个空的“教师”表的副本。 代码如下:USE studentGOSELECT * INTO 教师副本FROM 教师WHERE 1=2GO 上述代码中WHERE子句的条件永远为“假”,所以不会在创建的表中添加记录。在查询编辑器中输入并执行上述代码,用户可以查看到新建的表,但表中没有添加任何记录,如图5-24所示。
图5-24 创建教师空表副本5.2.7 集合查询 集合操作主要包括并操作UNION、交操作INTERSECT和差操作EXPECT。参加集合操作的各结果的列数量和对应的数据类型必须相同。 使用UNION语句可以将多个查询结果集合并为一个结果集,也就是集合的合并操作。UNION子句的语法格式如下: SELECT语句{UNION SELECT语句}[,…n] 其中:* 参加UNION操作的各结果集的列数必须相同,对应的数据类型也必须相同。* 系统将自动去掉并集的重复记录,如果要保留重复记录需使用UNION ALL操作符。* 最后结果集的列名来自第一个SELECT语句。 【例5.25】 查询“课程注册”表中选修了0001课程或者选修了0002课程的学生,也就是选修了课程0001的学生集合与选修了课程0002的学生集合的并集,且按课程号升序排列。 代码如下: USE studentGOSELECT *FROM 课程注册WHERE 课程号=’0001’UNIONSELECT * FROM 课程注册WHERE 课程号=’0002’ORDER BY 课程号 ASCGO 将上述代码在查询编辑器中输入并执行,可得到如图5-25所示的结果。
图5-25 查询结果的并操作 使用INTERSECT语句和EXCEPT语句的语法结构与UNION相似,此处不再赘述。 【例5.26】 查询“课程注册”表中既选修了0001课程又选修了0002课程的学生学号,即选修了课程0001的学生集合与选修了课程0002的学生集合的交集,结果按学号升序排列。图5-26显示了查询结果。代码如下: USE studentGOSELECT 学号FROM 课程注册WHERE 课程号=’0001’INTERSECTSELECT 学号 FROM 课程注册WHERE 课程号=’0002’ORDER BY 学号 ASCGO
图5-26 查询结果的交操作 【例5.27】 查询“课程注册”表中选修了0001课程而未选修0005课程的学生学号,即选修了课程0001的学生集合与选修了课程0005的学生集合的差集,结果按学号升序排列。如图5-27给出了查询结果。代码如下: USE studentGOSELECT 学号FROM 课程注册WHERE 课程号=’0001’EXCEPTSELECT 学号 FROM 课程注册WHERE 课程号=’0005’ORDER BY 学号 ASCGO
图5-27 查询结果的差操作5.3 连 接 查 询 5.2节所述查询是单表查询。若一个查询同时涉及两个或两个以上的表,则称为连接查询。连接查询是关系数据库中最主要的查询,包括等值与非等值查询、自然连接查询、自身连接查询、外连接查询和复合条件连接查询等。5.3.1 交叉连接查询 交叉连接又称非限制连接,也叫广义笛卡儿积,交叉连接的执行过程已在5.1节做了深入讨论。现给出其语法格式: SELECT 列表列名 FROM 表名1 CROSS JOIN 表名2 其中,CROSS JOIN为交叉表连接关键字。 【例5.28】 使用示例中的“学生”表、“专业”表,实现交叉查询。 代码如下: USE studentGOSELECT 学号,姓名,性别,学生.系部代码,学生.专业代码,专业.专业代码,专业名称,专业.系部代码FROM 学生 CROSS JOIN 专业GO 在查询分析器中输入并执行上述代码,结果如图5-28所示。
图5-28 交叉连接的执行结果 在例5.28的查询语句中,由于“学号”“姓名”“性别”和“专业名称”列在“学生”表、“专业”表中是唯一的,因此引用时可去掉表名前缀。而“系部代码”“专业代码”在两个表中都出现了,引用时必须加上表名前缀。 注意:多表查询时,如果要引用不同表中的同名属性,则在属性名前加表名,即用“表名.属性名”的形式表示,以便区分。 5.3.2 等值与非等值连接查询 用来连接两个表的条件称为连接条件或连接谓词,其一般格式为: [.] [.] 其中,比较运算符主要是=、>、=、<=、!=(或<>)。 当比较运算符为“=”时,称为等值连接。使用除等号外的其他运算符的称非等值连接。与比较运算符一起组成连接条件的列名称为连接字段。连接字段的类型必须是可比的,但名字不必相同。 在例5.28中,如果使用等值连接,其过程如下:把“学生”表中的每一条记录取出,与“专业”表中的第一条记录比较,如果“专业代码”列值相等(连接条件),则连接形成第一条记录,否则不连接;同样地,再取出“学生”表中的每一条记录,与“专业”表中的第二条、第三条、第四条……比较,若“专业代码”列值相等,则分别连接;否则不连接。这样的操作,要进行到“专业”表中的全部记录都处理完毕为止。 通过以上描述,可得出结论:等值连接的过程类似于交叉连接,不过,它只将满足连接条件的记录连接到结果集中。其语法格式为: SELECT 列表列名FROM 表名1 [INNER] JOIN表名2ON 表名1.列名=表名2.列名 其中,INNER是连接类型可选关键字,表示内连接,可以省略。“ON 表名1.列名=表名2.列名”是等值连接的连接条件。 【例5.29】 用等值连接方法连接“学生”表和“专业”表,观察通过“专业代码”连接后的结果与交叉连接的结果有何区别。 代码如下: USE studentGOSELECT 学号,姓名,性别,学生.系部代码,学生.专业代码,专业.专业代码,专业名称,专业.系部代码FROM 学生 INNER JOIN 专业 ON 学生.专业代码=专业.专业代码GO 在查询分析器中输入并执行上述代码,结果如图5-29所示。
图5-29 等值连接的执行结果 从结果中可以发现,只有满足连接条件的记录才被连接到结果集中,结果集是两个表的交集。在如图5-29所示的图中,“系部代码”“专业代码”列有重复。在等值连接中,把目标列中重复的属性列删除,称为自然连接。 【例5.30】 自然连接“学生”表和“专业”表。 代码如下: USE studentGOSELECT 学号,姓名,性别,学生.系部代码,专业.专业代码,专业名称FROM 学生 JOIN 专业 ON 学生.专业代码=专业.专业代码GO 在查询分析器中输入并执行上述代码,结果如图5-30所示。 例5-30中“系部代码”列和“专业代码”列在两表中都出现过,只需引用一个即可,但引用时必须加上相应的表名前缀。
图5-30 自然连接的执行结果5.3.3 自身连接查询 连接操作既可在多表之间进行,也可以是一个表与其自己进行连接,称为表的自身连接。使用自身连接时,必须为表指定两个别名,以示区别。 【例5.31】 使用“教师任课”表,查询至少为两个专业开设课程的教师编号和专业代码。 代码如下: USE studentGOSELECT first.教师编号,second.专业代码FROM 教师任课 AS first JOIN 教师任课 AS secondON first.教师编号=second.教师编号 AND first.专业代码!=second.专业代码GO 在查询分析器中输入并执行上述代码,结果如图5-31所示。
图5-31 自身连接的执行结果5.3.4 外连接查询 外连接的结果集不但包含满足连接条件的行,还包括相应表中的所有行,也就是说,即使某些行不满足连接条件,但仍需要输出该行记录。外连接包括三种:左外连接、右外连接和完全外连接。 1.左外连接 左外连接(Left Outer Join)是指结果表中除了包含满足连接条件的记录外,还包含左表中不满足连接条件的记录。 注意:左表中不满足条件的记录与右表记录连接时,右表的相应列上填充NULL值。左外连接的语法格式为: SELECT 列表列名FROM 表名1 LEFT [OUTER] JOIN 表名2ON 表名1.列名=表名2.列名 其中,OUTER关键字可省略。 【例5.32】 将“学生”表左外连接“成绩”表。 代码如下: USE studentGOSELECT 学生.学号,学生.姓名,性别,系部代码,语文,数学,英语,美术,自然,体育,音乐FROM 学生 LEFT OUTER JOIN 成绩 ON 学生.学号=成绩.学号GO 在查询分析器中输入并执行上述代码,结果如图5-32所示。其含义是:以“学生”表为主体列出每个学生的基本情况及其课程成绩,而无论该生是否有该门课程的成绩,若没有该门课成绩,则在相应位置填空值(Null),这就避免了在连接时舍弃成绩全为空的学生基本信息,即保留图中贾凌云、周红瑜、李晨、周春梅、张雪琪、李艾一6名学生的基本信息。
图5-32 左外连接的执行结果 2.右外连接 右外连接(Right Outer Join)是指结果表中除了包含满足连接条件的记录外,还包含右表中不满足连接条件的记录。 注意:右表中不满足条件的记录与左表记录连接时,左表的相应列上填充NULL值。右外连接的语法格式为: SELECT 列表列名FROM 表名1 RIGHT [OUTER] JOIN 表名2ON 表名1.列名=表名2.列名 其中,OUTER关键字可省略。 【例5.33】 将“学生”表右外连接“成绩”表。 代码如下: USE studentGOSELECT 学生.学号,学生.姓名,性别,系部代码,语文,数学,英语,美术,自然,体育,音乐FROM 学生 RIGHT OUTER JOIN 成绩 ON 学生.学号=成绩.学号GO 输入并执行上述代码的结果如图5-33所示。我们发现在连接时舍弃了成绩全为空的学生基本信息,即删除了图5-32中贾凌云、周红瑜、李晨、周春梅、张雪琪、李艾一的基本信息,表明该右外连接是以“成绩”表为主体列出每个学生的基本情况及其课程成绩的。
图5-33 右外连接的执行结果 3.完全外连接 同理,完全外连接(Full Outer Join)是指结果表中除了包含满足连接条件的记录外,还包含两个表中不满足连接条件的记录。 注意:左(右)表中不满足条件的记录与右(左)表记录连接时,右(左)表的相应列上填充NULL值。完全外连接的语法格式为: SELECT 列表列名FROM 表名1 FULL [OUTER] JOIN 表名2ON 表名1.列名=表名2.列名 其中,OUTER关键字可省略。5.3.5 复合连接条件查询 以上各个连接查询中,ON连接条件表达式只有一个条件,允许ON连接表达式有多个连接条件,称为复合条件连接,或多表连接。实际上,在例5-31中已经给出了多表连接的应用。这里再举一例。 【例5.34】 使用“学生”表、“课程”表和“课程注册”表,查询成绩在70~80分(含70分和80分)的学生学号、姓名、专业代码,选修课的课程号、课程名称以及对应的 成绩。 代码如下: USE studentGOSELECT S.学号,S.姓名,S.专业代码,C.课程号,CN.课程名,C.成绩FROM 学生 AS S JOIN 课程注册 AS CON S.学号=C.学号 AND C.成绩>=70 AND C.成绩<=80JOIN 课程 AS CNON C.课程号=CN.课程号GO 在查询分析器中输入并执行上述代码,结果如图5-34所示。
图5-34 复合连接条件的执行结果 用WHERE子句改写例5.34,可简化代码如下,其执行结果与图5-34一致: USE studentGOSELECT S.学号,S.姓名,S.专业代码,C.课程号,CN.课程名,C.成绩FROM 学生 AS S,课程注册 AS C, 课程 AS CNWHERE S.学号=C.学号 AND C.课程号=CN.课程号 AND C.成绩>=70 AND C.成绩<=80GO5.4 子 查 询 SQL语言作为一门超高级语言,继承了其他计算机语言的主要特征,例如,将要讲述的嵌套查询就类似于程序语言中的循环嵌套。通常把一个SELECT-FROM-WHERE语句组称为一个查询块。将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语条件中的查询称为嵌套查询(Nested Query)。例如: SELECT 姓名FROM 学生WHERE 学号 IN ( SELECT 学号 FROM 课程注册 WHERE 教师编号=’100000000001′ ) 括号内的查询块作为括号外WHERE子句的条件嵌入SQL语句中。我们把括号内的查询块称为子查询或内层查询,与之相对的概念就是父查询或外层查询,即包含子查询的查询块。SQL语言允许多层嵌套查询,但需要注意的是,子查询的SELECT语句中不能使用ORDER BY子句,ORDER BY子句只能对最终查询结果进行排序,也不能包括COMPUTE 或FOR BROWSE子句。 SQL Server 2012对嵌套查询的求解顺序是先内后外。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立父查询的查找条件。有了嵌套查询,可以用多个简单的查询构造复杂查询(嵌套不能超过32层),提高SQL语言的表达能力,以这样的方式来构造查询程序,层次清晰,易于实现,这正是SQL中“结构化(structured)”的内涵所在。 某些嵌套查询可用连接运算替代,某些则不能。到底采用哪种方法,用户可根据实际情况判断。5.4.1 带有IN谓词的子查询 在嵌套查询中,子查询的结果通常是一个集合。IN是嵌套查询中使用最频繁的谓词。其处理过程是:父查询通过IN谓词将父查询中的一个表达式与子查询返回的结果集进行比较,如果表达式的值等于子查询结果集中的某个值,父查询中的条件表达式返回真(TRUE),否则返回假(FALSE)。还可以在IN前加上关键字NOT,其功能与IN相反。 【例5.35】 使用“学生”表、“课程”表和“课程注册”表,查询选修了课程名为“高等数学”或“计算机导论”的学生的学号和姓名。 代码如下: USE studentGO
SELECT 学号,姓名FROM 学生WHERE 学号 IN (SELECT 学号 FROM 课程注册 WHERE 课程号 IN (SELECT 课程号 FROM 课程 WHERE 课程名=’高等数学’ OR课程名=’计算机导论’ ) )GO 例5.35涉及三个属性:学号、姓名和课程名。学号和姓名存放在“学生”表中,课程名存放在“课程”表中,两个表通过“课程注册”表建立联系,所以本例涉及三个关系(如上面标号所示): (1)在“课程”表中找到“高等数学”或“计算机导论”两课程的课程号,结果为0002或0003。 (2)在“课程注册”表中找出选修了(1)中课程的学生学号,结果为140101001001、140101001011、140201001001、140202002001、150102002001、150102002007、150102002018。 (3)在“学生”表中取出(2)中的学号和对应的姓名。 在查询分析器中输入并执行上述代码,结果如图5-35所示。
图5-35 带有IN运算符的子查询的执行结果 例5.35同样可用连接查询实现,代码如下,执行结果与图5-35一致: USE studentGOSELECT DISTINCT 学生.学号,姓名FROM 学生,课程注册,课程WHERE 学生.学号 = 课程注册.学号 AND 课程注册.课程号 = 课程.课程号 AND (课程名=’高等数学’ OR 课程名=’计算机导论’)GO5.4.2 带有比较运算符的子查询 5.4.1节示例中子查询的查询条件不依赖于父查询,这类子查询称为不相关子查询;反之,则称为相关子查询(Correlated Subquery)。 父查询与子查询之间通过比较运算符连接,便形成了带有比较运算符的子查询。其处理过程是:父查询通过诸如=、>、=、<=、!=或<>等比较运算符将父查询中的一个表达式与子查询返回的结果(单值)进行比较,如果表达式的值与子查询结果相比为真,那么,父查询中的条件表达式返回真(TRUE),否则返回假(FALSE)。 要强调的是,带有IN运算符的子查询返回的结果是集合,而带有比较运算符的子查询返回的结果是单值,而且用户在查询开始时就知晓“内层查询返回的是单值”这一事实。在书写带比较运算符的子查询时,注意子查询一定要跟在比较运算符之后。特殊地,若IN的子查询结果集为单值,则“=”符号和IN可以互换,如图5-36所示。
图5-36 查询与“王钢”(含王钢本人)同在一个系的教师基本信息 【例5.36】 使用“教师”表,查询与“王钢”同在一个系的教师基本信息。 代码如下: USE studentGOSELECT 教师编号,姓名,性别,学历,职务,职称FROM 教师WHERE 系部代码= (SELECT 系部代码 FROM 教师 WHERE 姓名=’王钢’ )GO 在查询分析器中输入并执行上述代码,结果如图5-36所示,结果集中包括“王钢”本人的情况,若要去掉“王钢”本人的情况,则代码改写为图5-37即可。
图5-37 查询与“王钢”(不含王钢本人)同在一个系的教师基本信息 【例5.37】 找出每个学生超过他所修课程平均成绩的课程号。 代码如下: USE studentGOSELECT 学号,课程号FROM 课程注册 AS xWHERE 成绩>= (SELECT AVG(成绩) FROM 课程注册 AS y WHERE y.学号=x.学号 )GO 其中,x和y都是课程注册表的别名。子查询是求解一个学生所有课程的平均成绩,至于是哪名学生的平均成绩要看x.学号的值,而该值是与父查询相关的,这就是相关子查询。上述语句的执行过程是: (1)从外层查询中取出“课程注册”表的一个元组,将其学号(如取出学号140101001001)的值传送给子查询,即: SELECT AVG(成绩)FROM 课程注册 AS yWHERE y.学号=’140101001001’ (2)执行子查询,得到近似结果78((87 74 71 69 90)÷5≈78),用该值代替子查询,得到父查询,即: SELECT 学号,课程号FROM 课程注册 AS xWHERE 成绩 >=78 (3)执行父查询,得到 (140101001001, 0001) /*0001号课程成绩87分*/(140101001001, 0005) /*0004号课程成绩90分*/ 接着,父查询取出下一个元组,重复上述(1)~(3)步,直到外层所有元组处理完毕,结果如图5-38所示。
图5-38 查询每个学生超过他所修课程平均成绩的课程号5.4.3 带有ANY或ALL谓词的子查询 子查询返回单值时可以使用比较运算符,但返回多值时则使用ANY或ALL谓词,还必须同时使用比较运算符,其语义如表5-24所示。表5-24 ANY或ALL谓词与比较运算符连用的语义表运 算 符语 义运 算 符语 义 >ANY大于子查询结果中的某个值 >ALL大于子查询结果中的所有值 =ANY大于或等于子查询结果中的某个值 >=ALL大于或等于子查询结果中的所有值 <=ANY小于或等于子查询结果中的某个值 <=ALL小于或等于子查询结果中的所有值 =ANY等于子查询结果中的某个值 =ALL等于子查询结果中的所有值 !=ANY或 <> ANY不等于子查询结果中的某个值 !=ALL 或 <>ALL不等于子查询结果中的所有值 带有ANY或ALL谓词的子查询,其处理过程是:父查询通过ANY或ALL谓词将父查询中的一个表达式与子查询返回结果集中的某个值进行比较,如果表达式的值与子查询结果相比为真,那么,父查询中的条件表达式返回真(TRUE),否则返回假(FALSE)。 ANY或ALL谓词与聚集函数、IN谓词的等价转换关系如表5-25所示。表5-25 ANY或ALL谓词与聚集函数、IN谓词的等价关系
=<>或!=或>=ANYIN—或>=MINALL—NOT IN或>=MAX 【例5.38】 使用“学生”表和“系部”表,查询其他系中比“计算机系”某一学生年龄小的学生信息。 代码如下: USE studentGOSELECT 学号,姓名,性别,出生日期,系部代码FROM 学生WHERE 系部代码<>(SELECT 系部代码 FROM 系部 WHERE 系部名称= ‘计算机系’ )AND 出生日期 >ANY (SELECT 出生日期 FROM 学生 WHERE 系部代码= (SELECT 系部代码 FROM 系部 WHERE 系部名称=’计算机系’) )ORDER BY 出生日期GO 在查询分析器中输入并执行上述代码,结果如图5-39所示。 注意:在例5.38中,做“>ANY”运算的并不是学生年龄,而是学生的出生日期(年龄越小,表示出生日期的数值越大),因此,用“>ANY”运算符。也可用聚集函数YEAR()、GETDATE()先将出生日期计算转换为年龄(若采用年龄参与比较运算,则“>ANY”应改写为“ /*用系统当前日期中的年份减去学生出生日期中的年份,得到学生年龄*/ 此外,本例还用到比较运算符“=”的子查询,通过“系部名称”查找对应的“系部代码”。AND前面的表达式是为了去除计算机系系内的学生信息。最后,要求结果按出生日期升序排列。
图5-39 查询其他系中比“计算机系”某一学生年龄小的学生信息 将例5.38改为查询其他系中比“计算机系”所有学生年龄都小的学生信息。只需把“>ANY”修改为“>ALL”即可,请读者自己实现代码并验证结果。 例5.38使用MAX()函数来实现:先用子查询找出计算机系中学生的最大年龄(年龄计算方法如前所述),接着在父查询中查找所有非计算机系且年龄小于该“最大年龄”的学生信息。 代码如下: USE studentGOSELECT 学号,姓名,性别,出生日期,系部代码FROM 学生WHERE 系部代码<>(SELECT 系部代码 FROM 系部 WHERE 系部名称= ‘计算机系’ )AND YEAR(GETDATE())-YEAR(出生日期) < (SELECT MAX(YEAR(GETDATE())-YEAR(出生日期)) AS 年龄 From 学生 WHERE 系部代码 =(SELECT 系部代码 FROM 系部 WHERE 系部名称=’计算机系’) )GO 5.4.4 带有EXISTS谓词的子查询 EXISTS是存在量词,使用EXISTS谓词的子查询不返回任何数据,此时,若子查询结果非空(即至少存在一条记录),则父查询的WHERE子句返回真(TRUE),否则返回假(FALSE)。 由EXISTS引出的子查询,其目标列通常都用“*”,原因在于该查询只返回逻辑值,给出列名毫无意义。正是因为EXISTS的这个用途,其查询效率不一定比不相关查询低,有时是一种高效的查询方法。 前面所讲的子查询,其查询条件不依赖于父查询,并且每个子查询都只执行一次,我们称之为不相关子查询。与此相对的概念是相关子查询,即查询条件依赖于父查询中的某个值,鉴于这种相关性(relativity),必须反复求值,供父查询使用。其处理过程是:取出父查询表中的第一条记录,根据它与子查询相关的属性值处理子查询,若子查询的WHERE子句返回真值,则把该条记录放入结果表中;然后再取父表的第二条记录;重复以上过程,直至父查询表全部处理完毕为止。 与EXISTS运算符相对的是NOT EXISTS,使用NOT EXISTS后,若子查询结果为空,则父查询的WHERE子句返回真(TRUE),否则返回假(FALSE)。 【例5.39】 用EXISTS谓词改写例5.36,即查询与“王钢”同在一个系的教师基本信息。 代码如下: USE studentGOSELECT 教师编号,姓名,性别,学历,职务,职称FROM 教师 AS T1WHERE EXISTS (SELECT * FROM 教师 AS T2 WHERE T2.系部代码=T1.系部代码 AND T2.姓名=’王钢’ )GO 在查询分析器中输入并执行上述代码,结果与例5.36一致,如图5-40所示。从本例中可以看出所有带IN谓词、比较运算符、ANY或ALL谓词的子查询都能使用带EXISTS运算符的子查询等价替换。
图5-40 用EXISTS谓词改写例5.36 【例5.40】 使用“学生”表和“课程注册”表,查询所有选修“计算机导论”课学生的学号和姓名。 代码如下: USE studentGOSELECT 学号,姓名FROM 学生WHERE EXISTS (SELECT * FROM 课程注册 WHERE 学号=学生.学号 AND 课程号= (SELECT 课程号 FROM 课程 WHERE 课程名=’计算机导论’ ) )GO 在查询分析器中输入并执行上述代码,结果如图5-41所示。
图5-41 用EXISTS谓词查询所有选修了“计算机导论”课的学生学号和姓名 【例5.41】 查询选修了全部课程的学生学号和姓名。 由于SQL语言中没有描述“全部”量词(For all),我们将该查询转译为“查询这样的学生:没有一门课程是他不选修的”。 代码如下: USE studentGOSELECT 学号,姓名FROM 学生WHERE NOT EXISTS (SELECT * FROM 课程 WHERE NOT EXISTS (SELECT * FROM 课程注册 WHERE 学号=学生.学号 AND 课程号=课程.课程号 ) )GO 在查询分析器中输入并执行上述代码,结果如图5-42所示。
图5-42 用NOT EXISTS实现全称量词的查询 5.3节、5.4节涉及的运算符基本上是二元运算符,即用这些运算符来“组合”两个或两个以上的关系(即表)。学习这两节时,要注意公共属性集合的问题:它是第一个关系与第二个关系(与第三个关系,……,与第n个关系)相联系的中间环节,尽管这些公共属性可能在各个关系上具有不同的名称,但是它们必须具有相同的域和含义,只要掌握了它们的“内涵”,并结合5.2节简单查询的知识,就能写出结构规范、运行高效的SQL多表查询语句。5.5 数据的添加、修改和删除 SQL Server数据库的新表建好后,表中并不包含任何记录,要想实现数据的存储,必须向表中添加数据。同样要实现表的良好管理,则需要经常修改表中的数据。本节主要介绍数据的添加、修改和删除。 在数据的基本操作中,常用到T-SQL语句,首先应掌握如表5-26所示的SQL语句的语法规则。表5-26 SQL语句的语法规则规 则含 义大写T-SQL关键字斜体T-SQL语法中用户提供的参数|(竖线)分隔括号或大括号内的语法项目。只能选择一个项目[ ](中括号)可选语法项目,不必输入中括号{ }(大括号)必选语法项目,不要输入大括号[,…n]表示前面的项可重复n次。每一项由英文逗号分隔[…n]表示前面的项可重复n次。每一项由空格分隔加粗数据库名、表名、列名、索引名、存储过程、实用工具、数据类型名以及必须按所显示的原样输入的文本::=语法块的名称。此规则用于对可在语句中多个位置使用的过长语法或语法单元部分进行分组和标记。适合使用语法块的每个位置由括在尖括号内的标签表示:5.5.1 数据的添加 向表中添加数据可以使用INSERT语句。INSERT语句的语法格式如下: INSERT [INTO] table_name [column_list] VALUES (data_values) 其中,各项参数的含义如下:* [INTO]是一个可选关键字,可以将它用在INSERT和目标表之间。* table_name是要添加数据的表名或table变量名称。* [column_list]是要添加数据的字段名称或字段列表,必须用中括号将column_list括起来,并且用逗号进行分隔。若没有指定字段列表,则指全部字段。* VALUES(data_values)用于引入添加记录的字段值。必须与column_list相对应。也就是说,每一个字段必须对应一个字段值,且必须用小括号将字段值列表括起来。如果VALUES列表中的值与表中列的顺序不相同,或者未包含表中所有列的值,那么必须使用column_list明确地指定存储每个传入值的列。 1.最简单的INSERT语句 【例5.42】 在结构如图5-43所示的“专业”表中添加一行记录:在计算机系部中添加一个电子商务专业。代码如下: USE student GOINSERT 专业 (专业代码,专业名称,系部代码)VALUES (‘0103′,’电子商务’,’01’)GO 在查询编辑器中输入上述代码,单击按钮,运行结果如图5-44和图5-45所示。 图5-44 简单添加数据语句 图5-45 查看运行结果 注意:VALUES列表中的表达式的数量必须匹配列表中的列数,表达式的数据类型应与列的数据类型相兼容。 2.省略清单的INSERT语句 【例5.43】 在结构如图5-46所示的“班级”表中添加“15级电子商务001班”。 代码如下: USE studentGOINSERT 班级VALUES (‘150103001′,’15级电子商务001班’,’0103′,’01’,NULL)GO 在查询编辑器中输入上述代码并执行,即可在“班级”表中增加如图5-47所示的值为“’150103001′,’15级电子商务001班’, ‘0103’, ’01’, NULL”的记录。 注意:此种方法省略了字段清单,用户必须按照这些列在表中定义的顺序提供每一个列的值,建议在输入数据时最好使用列清单。 图5-46 “班级”表结构 图5-47 执行添加语句后的结果 3.省略VALUES清单的INSERT语句 在T-SQL语言中,有一种简单的插入多行的方法。这种方法是使用SELECT语句查询出的结果代替VALUES子句。这种方法的语法结构如下: INSERT [INTO] table_name (column_name[,…n])SELECT column_name[,…n] FROM table_name WHERE search_conditions 其中,各项参数的含义如下: (1)search_conditions——查询条件。 (2)INSERT表和SELECT表的结果集的列数、列序、数据类型必须一致。 【例5.44】 创建“课程”表的一个副本“课程1”表,将“课程”表的全部数据添加到“课程1”表中。 代码如下: USE studentGOCREATE table 课程1(课程号 char(4) NOT NULL,课程名 char(20) NOT NULL,学分 smallint NULL)GOINSERT INTO 课程1(课程号,课程名,学分) SELECT 课程号,课程名,学分 FROM 课程GO 将上述代码在查询编辑器中运行,用户可以看到在“课程1”中增加了7行数据,如图5-48所示。
图5-48 增加多行数据语句执行结果 4.向学生选课系统各表中添加数据 根据需要,向学生选课系统的各表中添加数据,在查询编辑器中分别执行下列代码。 (1)向“系部”表中添加如图5-49所示的4条记录。代码如下: USE student GOINSERT 系部 (系部代码,系部名称,系主任)VALUES (’01’,’计算机系’,’徐才智’) GO … (a)“系部”表结构 (b)“系部”表中增加4条记录后的执行结果图5-49 表结构及增加4条记录后的执行结果 (2)向“专业”表添加如图5-50所示的8条记录。代码如下: USE student GOINSERT 专业 (专业代码,专业名称,系部代码)VALUES (‘0101′,’软件工程’,’01’) GO … (a)“专业”表结构 (b)“专业”表中增加8条记录后的执行结果图5-50 表结构及增加8条记录后的执行结果 (3)向“班级”表添加如图5-51所示的5条记录。代码如下: USE student GOINSERT 班级(班级代码,班级名称,专业代码,系部代码,备注)VALUES (‘140101001′,’14级软件工程001班’,’0101′,’01’,NULL)GO… (a)“班级”表结构 (b)“班级”表中增加5条记录后的执行结果图5-51 表结构及增加5条记录后的执行结果 (4)向“学生”表添加如图5-52所示的10条数据记录。代码如下: USE studentGOINSERT 学生VALUES (‘140101001001′,’张斌’,’男’,’1995-5-4′,’2014-9-1′,’140101001′, ’01’,’0101′)GO… (a)“学生”表结构 (b)“学生”表中增加10条记录后的执行结果图5-52 表结构及增加10条记录后的执行结果 (5)向“课程”表添加如图5-53所示的7条数据记录。代码如下: USE studentGOINSERT 课程(课程号,课程名,学分)VALUES (‘0001′,’大学英语’,’6′)GO… (a)“课程”表结构 (b)“课程”表中增加7条记录后的执行结果图5-53 表结构及增加7条记录后的执行结果 (6)向“教学计划”表添加如图5-54所示的42条数据记录。代码如下:USE studentGOINSERT 教学计划(课程号,专业代码,专业学级,课程类型,开课学期,学分)VALUES (‘0001′,’0101′,’2014′,’公共必修’,’1′,’6′)GO… (a)“教学计划”表结构 (b)“教学计划”表中增加42条记录后的部分执行结果图5-54 表结构及增加42条记录后的执行结果 (7)向“教师”表添加如图5-55所示的5条数据记录。代码如下: USE studentGOINSERT 教师(教师编号,姓名,性别,出生日期,学历,职务,职称,系部代码,专业,备注)VALUES (‘100000000001′,’张学杰’,’男’,’1969-1-1′,’硕士’,’主任’,’教授’,’01’, ‘计算机’,NULL)GO… (a)“教师”表结构 (b)“教师”表中增加5条记录后的执行结果图5-55 表结构及增加5条记录后的执行结果 (8)向“教师任课”表添加如图5-56所示的42条数据记录。代码如下: USE studentGOINSERT 教师任课(教师编号,课程号,专业学级,专业代码,学年,学期,学生数)VALUES(‘100000000001′,’0002′,’2014′,’0101′,’2014’,2,0)GO… (a)“教师任课”表结构 (b)“教师任课”表中增加42条记录后的部分执行结果图5-56 表结构及增加42条记录后的执行结果 (9)利用“学生”表、“教师任课”表、“教学计划”表向“课程注册”表添加如图5-57所示的36条数据记录(注意,若学生完成该门课程学习,还需手动修改成绩、学分列的值或使用触发器来自动修改学分列的值,具体内容参见10.2节)。代码如下: USE studentGOINSERT 课程注册(学号,课程号,教师编号,专业代码,专业学级,选课类型,学期,学年,成绩,学分)SELECT DISTINCT 学生.学号,教师任课.课程号,教师任课.教师编号,学生.专业代码,教师任课.专业学级,教学计划.课程类型,教师任课.学期,教师任课.学年,0,0FROM 学生,教师任课,教学计划WHERE 教师任课.专业学级=YEAR(学生.入学时间) AND 教师任课.专业代码=学生.专业代码 AND 教师任课.专业代码=教学计划.专业代码 AND 教师任课.课程号=教学计划.课程号 AND 教师任课.专业学级=教学计划.专业学级GO (a)“课程注册”表结构 (b)“课程注册”表中增加36条记录后的部分执行结果图5-57 表结构及增加36条记录后的执行结果5.5.2 数据的修改 在数据输入过程中,可能会出现输入错误,或是因为时间变化而需要更新数据,这都需要修改数据。修改表中的数据可以使用SQL Server Management Studio中的图形界面进行修改,即右击某数据表图标,在弹出的快捷菜单中选择“编辑前200行”命令,在打开的“表数据窗口”中进行修改。这里主要介绍T-SQL的UPDATE语句实现修改的方法,UPDATE的语法格式如下: UPDATE table_nameSET{column_name={expression|DEFAULT|NULL}}[,…n][FROM{
评论
还没有评论。