文章目录
所有操作均在 Oracle 数据库上进行
第三章 - 关系数据库标准语言 SQL
3.1 SQL 概述
3.1.1 结构化查询语言 SQL
SQL 是一种介于关系代数与关系演算之间的语言,
功能包括 查询、操纵、定义和控制四个方面。
3.1.2 SQL 体系结构
1. 外模式 - 视图和部分基本表
2. 模式 - 基本表,元组称为行,属性称为列
3. 内模式 - 存储文件
3.1.3 SQL 的组成
1. 数据操作语言 - 删插改查 行
2. 数据定义语言 - 增删改 表 ;增删 索引、视图
3. 数据控制语言 - 控制管理用户对数据库对象的访问
4. 触发器和高级完整性约束
5. 嵌入式和动态 SQL - 嵌套在高级语言中,允许在运行时构建查询
6. 客户 - 服务器执行和远程数据库提取
7. 事物管理 - 显式控制事务执行
3.1.3 SQL 的特点
1. 综合统一: 集数据定义、操纵、控制语言于一体(DDL、DML、DCL);独立完成数据库生命周期的全部活动,随时修改,数据操作符统一。
2. 高度非过程化: SQL 只需提出”做什么“,无需了解存取路径。
3. 面向集合的操作方式: 面向记录操作,结果、对象可以是元组的集合。
4. 以同一种语法结构提供多种使用方式: 联机交互,嵌入式。
5. 语言简洁:
3.2 数据定义
3.2.1 基本表的操作
1. 定义基本表
CREATE TABLE 表名(
列名 数据类型 完整性约束,
列名 数据类型 完整性约束,
表级完整性约束(列名)
)
完整性约束:存入系统的数据字典中,DMBS自动检查
完整性约束条件
1.重名名约束条件:constraint 约束名字 约束
2.主码约束:primary key
3.外码约束:
行级:references 表名(列名)
表级:foreign key (列名) references 表名(列名)
4.check约束:check(条件)
5.NOT NULL约束:
6.UNIQUE约束:
7.DEFAULT约束:default('值')
2. 修改基本表
ALTER TABLE 表名 操作 列
1.添加列:ALTER TABEL 表名 ADD 列名 数据类型 完整性约束
ALTER TABEL 表名 ADD(
列名 数据类型 完整性约束,
列名 数据类型 完整性约束)
2.删除列:ALTER TABEL 表名 DROP COLUMN 列名
ALTER TABEL 表名 DROP (列名, 列名)
3.修改列:ALTER TABEL 表名 MODIFY 列名 数据类型 完整性约束
4.删除约束:ALTER TABLE 表名 DROP CONSTRAINT 约束名
ALTER TABLE 表名 DROP 约束(列名) ---Oracle不支持---
删除 UNIQUE 或 PRIMARY KEY 约束可能导致由其生成的索引被删除
3. 删除基本表
DROP TABLE 表名
3.2.2 索引的操作
1. 建立索引
CREATE 选项 INDEX 索引名 ON 表名(列名 次序, 列名 次序)
选项:
UNIQUE 表明每一个索引值只对应唯一的数据记录
CLUSTER 表明建立聚簇索引
在 Oracle 中,不能对主键建立唯一索引,创建约束时系统自动创建
聚簇索引指表中记录的物理顺序与索引相同的索引组织,只能建立一个
在 Oracle 中,只能在定义表的同时定义
在常用的查询列上定义索引可以提高查询效率
对于经常更新的表不宜建立聚簇索引
次序:
ASC 升序
DESC 降序
默认值为升序
2. 删除索引
DROP INDEX 索引名
索引建立后由系统维护,建立索引可以检查查询时间,但若数据增删频繁,系统会花费大量时间维护
3.3 基本数据查询
SELECT [ALL/DISTINCT] 目标列表达式,目标列表达式
FROM 表/视图, 表/视图
[WHERE 条件]
[GROUP BY 列名 [HAVING 条件] ]
[ORDER BY 列名 [次序] ]
3.3.1 SELECT 子句
SELECT [ALL/DISTINCT] 目标列表达式,目标列表达式
1. 关键字 DISTINCT
从 SELECT 语句的结果中去除重复的行(针对后面的所有列,即针对元组),默认值为 ALL
2. 目标列表达式
目标表达式可以为算术表达式,字符串常量,函数,列别名
1. 查询指定列:列名
2. 查询全部列:*
3. 算术表达式:数值 运算符 列名
4. 指定别名:列名 别名
列表达式 "别名"
5. 指定列的默认值:'字符串' 列名
6. 函数:LOWER(列名), UPPER(列名) 将列中所有值设置为小/大写。
3.3.2 WHERE 子句
[WHERE 条件]
查询结果为指定条件的元组
1. 比较
比较数值或 字符ascii 码大小
2. 确定范围
选出两个值及其之间的数据,可以是日期,数字,文字
3. 确定集合
IN(值,值)
4. 字符匹配
LIKE 通配字符串 [ESCAPE '转义符']
1. 通配字符串:
% 任意或多个字符
_ 单个字符
2. 设置转义符:
对于字符串本来存在 % 和 _ 的情况,需要设置转义符转义
5. 空值查询
空值和其他值没有可比性,不能用 = 代替 IS
列名 IS NOT NULL
6. 多重条件
AND 优先级高于 OR,但可用括号改变
3.2.3 ORDER BY 子句
[ORDER BY 列名 [次序] ]
指定按照一个或多个属性列进行升降序排列结果,NULL 被视为最大值
3.2.4 聚集函数
COUNT([DISTINCT/ALL] *) 统计元组个数
COUNT([DISTINCT/ALL] 列名) 统计一列中值的个数
SUM([DISTINCT/ALL] 列名) 列总和,必须为数值型的列
AVG([DISTINCT/ALL] 列名) 列平均,必须为数值型
MAX([DISTINCT/ALL] 列名) 最大值
MIN([DISTINCT/ALL] 列名) 最小值
默认统计重复值
除指定了 * ,函数只处理非空值
WHERE 子句不能使用聚集函数
示例:
SELECT AVG(Sage)
FROM Student;
非法查询方式
SELECT Sname,MAX(Sage)
FROM Student;
合法查询方式
SELECT Sname,Sage
FROM Student
WHERE Sage=(SELECT MAX(Sage) FROM Student);
3.2.5 GROUP BY 和 HAVING 子句
GROUPBY 必须是集合操作(聚集函数),不能进行元组操作
[GROUP BY 列名 [HAVING 条件] ]
GROUP BY 可以将查询结果的各行按一列或多列取值相等的原则进行分组
在用聚集函数时一般都要用到GROUP BY进行分组,再用函数计算
计算完可以用HAVING子句进行判断
示例:
查询每个学生选修的课程数。
SELECT Sno, COUNT(Cno)
FROM SC
GROUP BY Sno;
查询平均分在80分以上的学生的学号及其选课数。
SELECT Sno,Count(Cno)
FROM SC
GROUP BY Sno
HAVING AVG(Grade)>80;
3.4 连接查询
一个查询需要对多个表进行操作,称为连接查询。
3.4.1 WHERE 子句连接
1. 等值与非等值连接
SELECT 目标表达式
FROM 表1,表2
WHERE 表1.列名 比较符 表2.列名
或者
WHERE 表1.列名 BETWEEN 表2.列名 AND 表3.列名
2. 笛卡儿积连接
SELECT *
FROM 表1,表2
3. 自然连接
按照表中相同的属性进行等值连接,并去掉目标列中重复的属性列
SELECT 不重复的属性列表
FROM 表1,表2
WHERE 表1.列名 = 表2.列名
4. 自身连接
一个表与自己进行连接
查询每一门课的间接先修课,即先修课的先修课。
SELECT FIRST.Cno, SECOND. Cpno
FROM Course FIRST, Course SECOND
WHERE FIRST. Cpno =SECOND.Cno;
5. 外连接
以Student表为主体列出每个学生的基本情况及其选课情况。
SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM Student, SC
WHERE Student.Sno=SC.Sno(+);
6. 复合条件连接
查询选修2号课程且成绩在90分以上的所有学生。
SELECT Student.Sno, Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno AND SC.Cno=2 AND SC.Grade>90;
3.4.2 FROM 子句连接
SELECT 目标表达式
FROM 表1 连接类型 表2
ON 条件
连接类型:
1.内连接:[INNER] JOIN - 等值、不等值、自然连接
2.外连接:LEFT [OUTER] JOIN - 左外连接
RIGHT [OUTER] JOIN - 右外连接
FULL [OUTER] JOIN - 全外连接
3.交叉连接:CROSS JOIN - 笛卡儿积连接
3.5 嵌套查询
将一个查询嵌套在另一个查询里,子查询本身也可以是嵌套查询
子查询通常出现在 WHERE 子句,有时也出现在 FROM 子句,有时也出现在 HAVING 短语中
子查询的 SELECT 语句不能使用 ORDER BY ,只能对最终结果 ORDER BY
不相关与相关子查询
不相关子查询:子查询都在父查询处理前求解,子查询只执行依次
相关子查询:子查询依赖于父查询的某个条件。
先取外层查询中的第一个元组,根据其与内层查询相关的属性值处理内层查询。
若 WHERE 子句返回值为真,则取此元组放入结果表。
重复此过程,直至外层表全部检查完成。
3.5.1 比较运算符子查询
---不相关子查询---
利用子查询完成
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept =(
SELECT Sdept
FROM Student
WHERE Sname= '刘晨'
);
用自身连接完成
SELECT S1.Sno,S1.Sname,S1.Sdept
FROM Student S1,Student S2
WHERE S1.Sdept = S2.Sdept AND S2.Sname = '刘晨'
---相关子查询---
找出每个学生超过他选修课程平均成绩的课程号。
SELECT Sno, Cno
FROM SC x
WHERE Grade >= (SELECT AVG(Grade)
FROM SC y
WHERE y.Sno=x.Sno
);
3.5.2 IN 子查询
查询所有选修了1号课程的学生的学号、姓名
SELECT Sno,Sname
FROM Student
WHERE Sno IN (
SELECT Sno
FROM SC
WHERE Cno=1
);
利用连接查询来实现
SELECT Student.Sno, Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno AND Cno=1;
3.5.3 BETWEEN AND 子查询
查找从19岁到 Student 表中年龄最大之间的学生学号和姓名
SELECT Sno,Sname
FROM Student
WHERE Sage BETWEEN 19 AND (
SELECT MAX(Sage)
FROM Student
);
3.5.4 ALL 和 ANY 子查询
ALL 要求所有,ANY 只要有一个就行
查询年龄比数学系最小的学生还小的学生学号和姓名。
SELECT Sno,Sname FROM Student
WHERE Sage < ALL(
SELECT Sage FROM Student
WHERE Sdept=‘MA’
);
比任何一个学生小就行,不是最小
SELECT Sno,Sname FROM Student
WHERE Sage < ANY(
SELECT Sage FROM Student
WHERE Sdept=‘MA’
);
3.5.5 EXISTS 子查询
EXISTS 子查询只返回逻辑值 true 和 false,结果非空为 true,结果空为 false
NOT EXISTS 相反
一些带EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换
所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换
1. 存在量词 - 反 E
查询所有选修了1号课程的学生姓名
---相关子查询---
SELECT Sname
FROM Student
WHERE EXISTS (
SELECT *
90 FROM SC
WHERE Sno=Student.Sno AND Cno=1
);
其它实现方法
---不相关子查询---
SELECT Sname
FROM Student
WHERE Sno IN (
SELECT Sno
FROM SC
WHERE Cno=1
);
SELECT Sname
FROM Student
WHERE Sno=ANY (
SELECT Sno
FROM SC
WHERE Cno=1
);
2. 全称量词 - 倒 A
---相关子查询---
查询选修了全部课程的学生姓名
SELECT Sname
FROM Student ---选择了一个学生---
WHERE NOT EXISTS( ---一个学生未选集合判空---
SELECT *
FROM Course ---选择了一门课程---
WHERE NOT EXISTS( ---生成一个学生未选课程集合---
SELECT * ---从 SC 表中找对应记录---
FROM SC
WHERE Sno= Student.Sno
AND Cno= Course.Cno
)
);
查询至少选修了学生200215122选修的全部课程的学生号码
SELECT DISTINCT Sno
FROM SC SCX ---选择了一条记录 X ---
WHERE NOT EXISTS( ---一个 X 集合判空---
SELECT *
FROM SC SCY ---选择指定的 Y ---
WHERE SCY.Sno = '200215122'
AND NOT EXISTS ( ---一个 X 找不到 Y 课程的集合---
SELECT *
FROM SC SCZ ---寻找一条记录 ---
WHERE SCZ.Sno=SCX.Sno ---匹配选中的 X ---
AND SCZ.Cno=SCY.Cno ---检查是否包含 Y 的课程 ---
)
);
3.6 集合查询
SQL 查询的结果是多行的集合
SQL 提供了三种集合操作,并操作 UNION,交操作 INTERSECT,差操作 EXCEPT,其中 ORACLE 中差操作用 MINUS 表示
3.6.1 并操作 UNION
UNION 可将多个查询结果合并起来,形成一个完整的查询结果,系统会去点重复的元组。
参加 UNION 操作的各数据项的数目及数据类型必须相同。
查询选修1号课程或者选修2号课程的学生学号
SELECT Sno
FROM SC
WHERE Cno=1
UNION
SELECT Sno
FROM SC
WHERE Cno=2
3.6.2 交操作 INTERSECT
查询选修1号课程和2号课程的学生姓名
SELECT Sname
FROM SC,Student
WHERE Cno=1 AND Student.Sno=SC.Sno
INTERSECT
SELECT Sname
FROM SC,Student
WHERE Cno=2 AND Student.Sno=SC.Sno
3.6.3 差操作 EXCEPT / MINUS
查询选修1号课程但是没有选修2号课程的学生学号
SELECT Sno
FROM SC
WHERE Cno=1
MINUS
SELECT Sno
FROM SC
WHERE Cno=2
3.7 数据更新
3.7.1 插入数据
若某些属性列在 INTO
中没有出现,则新记录中该列去取空值。
若定义表时某属性列设置了 NOT NULL
,不能为空值。
若 INTO
子句没有指明列名,则新插入的记录必须在某个属性列上均有值。
1. 插入元组
INSERT
INTO 表名(列名, 列名)
VALUES (常量、常量);
示例:
INSERT
INTO Course
VALUES (10, '网络技术', 5, 2);
INSERT
INTO SC(Sno, Cno)
VALUES (1001, 10);
2. 与子查询结合
INSERT
INTO 表名(列名, 列名)、
(子查询)
示例:
对每门课程,求学生的平均分数,并把结果存入数据库
INSERT
INTO AvgGrade(Cno, AvgGrade)
(SELECT Cno, AVG(Grade)
FROM SC GROUP BY Cno);
3.7.2 修改数据
更新表中数据,必须提供表名及 SET
表达式,可加 WHERE
限制更新的记录范围。
1. 修改元组
UPDATE 表名
SET 列名=表达式, 列名=表达式
[WHERE 条件]
示例:
将学号为1001的学生的年龄改为20岁
UPDATE Student
SET Sage=20
WHERE Sno=1001;
将所有学生的年龄增加1岁。
UPDATE Student
SET Sage=Sage+1;
2. 与子查询结合
语句执行时,将修改使子查询为真的所有元组。
UPDATE 表名
SET 列名=表达式, 列名=表达式
[WHERE 子查询条件表达式]
示例:
将数学系有成绩学生的分数更新为原分数的1.2倍
UPDATE SC
SET Grade = Grade * 1.2
WHERE Sno IN
(SELECT Sno
FROM Student
WHERE Sdept = 'MA')
3.7.3 删除数据
删除指定表中满足 WHERE
子句条件的所有元组,如果省略 WHERE
子句,表示删除表中全部元组,但表的定义仍存在与数据字典中。即删除的是表中数据,而不是表的定义。
1. 删除元组
DELETE
FROM 表名
[WHERE 条件]
示例:
删除性别是男的学生记录。
DELETE
FROM Student
WHERE Ssex='男';
删除的学生选课记录。
DELETE
FROM SC;
2. 与子查询结合
DELETE
FROM 表名
[WHERE 子查询条件表达式]
示例:
删除数学系选课学生的选课记录。
DELETE Sc
WHERE Sno IN
(SELECT Sno
FROM Student
WHERE Sdept= 'MA');
或者
DELETE
FROM SC
WHERE 'MA'=
(SELETE Sdept
FROM Student
WHERE Student.Sno=SC.Sno);
3.8 视图
视图是一个基于一个表或多个表或视图的逻辑表,视图基于的表称为虚表
视图只存储视图的定义,没有存储对应的数据,只是一个虚表
视图在打开的瞬间通过定义从基表中搜集数据,并展现给用户
通过视图可以对表里的数据进行查询和修改
3.8.1 视图的优点
- 简单性:分割数据,简化观点,把用户注意力集中到所关心的数据列,简化浏览数据的工作。
- **逻辑数据独立性:**为数据提供一定的逻辑独立。基本表的内容发生改变,不会影响视图定义所得到的数据。
- **安全性:**提供给自动的安全保护功能,视图能像基本表一样授予或者撤销访问许可。
- 试图可以间接对表进行更新,视图的更新就是表的更新。
3.8.2 创建视图
CREATE VIEW 视图名(列名, 列名)
AS 子查询
[WITH CHECK OPTION]
子查询可以是任意复杂的 SELECT
语句,但通常不允许含有 ORDER BY
和DISTINCT
短语。
WITH CHECK OPTION
表示对视图进行 UPDATE
INSERT
DELETE
操作时要保证进行操作的行满足视图定义中的谓词条件,即子查询中的条件表达式。
若 CREATE VIEW
仅指定了视图名,则隐含该属性由子查询中的 SELECT
子句目标列中的字段组成。以下三种情况必须指定视图的所有列名:
- 其中某个目标列不是单纯的属性名,而是聚集函数或列表达式
- 多表连接时选出了几个同名列作为视图的字段
- 需要在视图中为某个列启用别名
组成视图的属性列名必须按照上面的原则全部省略或全部指定
建立数学系学生的视图。
CREATE VIEW MA_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept='MA';
DBMS
执行 CREATE VIEW
语句的结果只是把对视图的定义存入数据字典,并不执行其中的 SELECT
语句。在对视图进行查询时,才按视图的定义从基本表中将数据查出。
建立数学系学生的视图,并要求进行修改和插入操作时仍需要保证该视图只有数学系的学生。
CREATE VIEW MA_Student
AS
SELECT Sno, Sname, Sage ,sdept
FROM Student
WHERE Sdept='MA'
WITH CHECK OPTION;
视图不仅可以建立在单个基本表上,也可以建立在多个基本表上,也可以建立在一个或多个已定义好的视图上,或同时建立在基本表与视图上。
建立数学系选修了1号课程的学生的视图
CREATE VIEW MA_S1(Sno, Sname, Grade)
AS
SELECT Student.Sno, Sname, Grade
FROM Student, SC
WHERE Sdept='MA' AND
Student.Sno=SC.Sno AND
SC.Cno=1;
建立数学系选修了1号课程且成绩在90分以上的学生的视图
CREATE VIEW MA_S2
AS
SELECT Sno, Sname, Grade
FROM MA_S1
WHERE Grade>=90;
视图中的出生年份是一个表达式,定义视图时必须明确定义视图的各属性列名。
定义一个反映学生出生年份的视图
CREATE VIEW BT_S(Sno, Sname, Sbirth)
AS SELECT Sno, Sname, 2013-Sage
FROM Student;
利用带有 集合函数
和 GROUP BY
子句的查询来定义的视图称为分组视图。
将学生的学号及他的平均成绩定义为一个视图。
CREAT VIEW S_G(Sno, Gavg)
AS SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno;
将Student表中所有女生记录定义为一个视图。
CREATE VIEW F_Student(Sno,name,sex,age,dept)
AS SELECT *
FROM Student
WHERE Ssex='女';
3.8.3 删除视图
一个视图被删除后,由此视图导出的其他视图也将失效,应一一删除。
DROP VIEW 视图名;
3.8.4 查询视图
用户可以像对基本表一样对视图进行查询。
DBMS
执行对表的查询时,首先进行有效性检查,若存在则从数据字典中取出涉及的视图定义,把定义中的子查询和用户对视图的查询结合起来,转换成对基本表的查询。
将对视图的查询转换为对基本表的查询的过程称为视图的消解。
在数学系学生的视图中找出年龄小于20岁的学生。
SELECT Sno, Sage
FROM MA_Student
WHERE Sage<20;
查询数学系选修了1号课程的学生。
SELECT Sno, Sname
FROM MA_Student, SC
WHERE MA_Student.Sno=SC.Sno AND SC.Cno=1;
3.8.5 更新视图
更新视图包括 INSERT
DELETE
UPDATE
三类
由于视图是不实际存储数据的虚表,因此对视图的更新最终要转换为对基本表的更新。
为防止用户通过视图对数据进行增删改时无意或故意操作不属于视图范围内的基本表数据,可在定义视图时加上 WITH CHECK OPTION
。
将数学系学生视图MA_Student中学号为20070001的学生姓名改为“刘玲”。
UPDATE MA_Student
SET Sname='刘玲'
WHERE Sno=20070001;
向数学系学生视图MA_Student中插入一个新的学生记录,其中学号为20070007,姓名为赵新,年龄为20岁。
INSERT
INTO MA_Student
VALUES(2007007, '赵新', 20);
删除数学系学生视图MA_Student中学号为20070001。
DELETE
FROM MA_Student
WHERE Sno=20070001