第三章 关系数据库标准语言SQL
3.1 SQL概述
SQL 功能 | 动词 |
|---|---|
| 数据查询 | SELECT |
| 数据定义 | CREATE, DROP, ALTER |
| 数据操纵 | INSERT, UPDATE, DELETE |
| 数据控制 | GRANT, REVOKE |
SQL支持关系数据库三级模式结构
<作图>
- 基本表
- 存储文件
- 视图
3.2 学生-课程数据库
学生表 | Student(Sno,Sname,Ssex,Sage,Sdept)
课程表 | Course(Cno,Cname,Cpno,Ccredit)
学生选课表 | SC(Sno,Cno,Grade) 3.3 数据定义
| 操作对象 | 创建 | 删除 | 修改 |
|---|---|---|---|
| 模式 | CREATE SCHEMA | DROP SCHEMA | |
| 表 | CREATE TABLE | DROP TABLE | ALTER TABLE |
| 视图 | CREATE VIEW | DROP VIEW | |
| 索引 | CREATE INDEX | DROP INDEX |
3.3.1 模式的定义与删除
定义模式
CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;
create schema <模式名> authorization <用户名>;如果没有指定 <模式名>,那么 <模式名> 隐含为 <用户名>
定义模式实际上定义了一个命名空间。在这个空间中可以定义该模式包含的数据库对象,例如基本表、视图、索引等。
删除模式
DROP SCHEMA <模式名> <CASCADE|RESTRICT>;- 删除模式的同时把该模式中所有的数据库对象全部删除
- 如果该模式中定义了下属的数据库对象(如表、视图等),则拒绝该删除语句的执行。当该模式中没有任何下属的对象时 才能执行。
CASCADE(级联)RESTRICT(限制)3.3.2 基本表的定义、删除与修改
定义基本表
CREATE TABLE <表名>
(
<列名> <数据类型> <列级完整性约束条件>,
<列名> <数据类型> <列级完整性约束条件>,
<列名> <数据类型> <列级完整性约束条件>
<表级完整性约束条件>
);建立学生表Student,学号是主码,姓名取值唯一。
CREATE TABLE Student
(
Sno CHAR(9) PRIMARY KEY, /* 列级完整性约束条件*/
Sname CHAR(20) UNIQUE, /* Sname取唯一值*/
Ssex CHAR(2),
Sage SMALLINT,
Sdept CHAR(20)
); 建立一个“学生选课”表SC
CREATE TABLE SC
(
Sno CHAR(9),
Cno CHAR(4),
Grade SMALLINT,
PRIMARY KEY (Sno, Cno), /* 作为表级完整性进行定义*/
FOREIGN KEY (Sno) REFERENCES Student(Sno), /* 表级完整性约束条件,Sno是外码,被参照表是Student */
FOREIGN KEY (Cno) REFERENCES Course(Cno) /* 表级完整性约束条件, Cno是外码,被参照表是Course*/
); 数据类型
| 数据类型 |
|---|
CHAR(n) |
VARCHAR(n) |
INT |
SMALLINT |
NUMERIC(p, d) |
REAL |
Double Precision |
FLOAT(n) |
DATE |
TIME |
模式与表
- 每一个基本表都属于某一个模式
- 一个模式包含多个基本表
- 定义基本表所属模式
DBA用户可以设置搜索路径,然后定义基本表
SET search_path TO “S-T”,PUBLIC;
Create table Student(......); 修改基本表
ALTER TABLE <表名>
ADD <新列名> <数据类型> 完整性约束
DROP <完整性约束名>
ALTER COLUMN<列名> <数据类型>;
ALTER TABLE Student
ADD S_entrance DATE;
ALTER TABLE Student
ALTER COLUMN Sage INT;
ALTER TABLE Course
ADD UNIQUE(Cname);删除基本表
DROP TABLE <表名> [RESTRICT| CASCADE];3.3.3 索引的建立与删除
一、建立索引
语句格式
CREATE [UNIQUE] [CLUSTER] INDEX <索引名>
ON <表名>
(
<列名> [<次序>],
<列名> [<次序>],
<列名> [<次序>],
);
CREATE CLUSTER INDEX Stusname
ON Student(Sname);
CREATE UNIQUE INDEX Stusno
ON Student(Sno);
CREATE UNIQUE INDEX Coucno
ON Course(Cno);
CREATE UNIQUE INDEX SCno
ON SC(Sno ASC,Cno DESC)CLUSTER为聚簇索引(指索引项的顺序与表中记录的物理顺序一致的索引组织)。一个表只有一个。UNIQUE表示唯一索引。
二、删除索引
DROP INDEX <索引名>;3.4 数据查询
3.4.1 单表查询
一、 选择表中的若干列
-- 小写字母
SELECT Sname,'Year of Birth:', 2004-Sage, LOWER(Sdept)
FROM Student;
-- 列别名
SELECT Sname NAME, 'Year of Birth:' BIRTH, 2000-Sage BIRTHDAY, LOWER(Sdept) DEPARTMENT
FROM Student;二、选择表中的若干元组
1.消除取值重复的行,如果没有指定DISTINCT关键词,则缺省为ALL
SELECT DISTINCT Sno
FROM SC; | 查询条件 | 谓词 |
|---|---|
| 比较 | =,>,<,>=,<=,!=,<>,!>,!<,NOT |
| 确定范围 | BETWEEN AND |
| 确定集合 | IN |
| 字符匹配 | LIKE |
| 空值 | IS NULL, IS NOT NULL |
| 多重条件(逻辑运算) | AND, OR, NOT |
WHERE Sage BETWEEN 20 AND 23;
WHERE Sage NOT BETWEEN 20 AND 23;
WHERE Sdept IN ( 'IS','MA','CS' );
WHERE Sdept NOT IN ( 'IS','MA','CS' );
-- 匹配串为固定字符串
WHERE Sno LIKE '200215121';
-- 匹配串为含通配符的字符串 (% 、_)
WHERE Sname LIKE '刘%';
WHERE Sname LIKE '欧阳_ _';
-- 使用换码字符将通配符转义为普通字符
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
-- ESCAPE '\' 表示“ \” 为换码字符
三、ORDER BY子句
ASC:排序列为空值的元组最后显示DESC:排序列为空值的元组最先显示
四、聚集函数
COUNTSUMAVGMAXMIN
SELECT COUNT(*)
SELECT COUNT(DISTINCT Sno)五、GROUP BY子句
SELECT Cno, COUNT(Sno)
FROM SC
GROUP BY Cno;SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >3;HAVING短语与WHERE子句的区别:
- 作用对象不同
WHERE子句作用于基表或视图,从中选择满足条件的元组HAVING短语作用于组,从中选择满足条件的组
3.4.2 连接查询
连接查询:同时涉及多个表的查询
嵌套循环法(NESTED-LOOP)
首先在表1中找到第一个元组,然后从头开始扫描表2,逐一查找满足连接件的元组,找到后就将表1中的第一个元组与该元组拼接起来,形成结果表中一个元组。
表2全部查找完后,再找表1中第二个元组,然后再从头开始扫描表2,逐一查找满足连接条件的元组,找到后就将表1中的第二个元组与该元组拼接起来,形成结果表中一个元组。
- 重复上述操作,直到表1中的全部元组都处理完毕
一、等值与非等值连接查询
等值连接:连接运算符为=
SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno = SC.Sno;自然连接:等值连接中把目标列中重复的属性列去掉
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno = SC.Sno;二、自身连接
- 自身连接
- 一个表与其自己进行连接 需要给表起别名以示区别 由于所有属性名都是同名属性,因此必须使用别名前缀
SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;三、外连接
外连接与普通连接的区别
- 普通连接操作只输出满足连接条件的元组
- 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade
FROM Student
LEFT OUT JOIN SC ON (Student.Sno=SC.Sno); 四、复合条件连接
复合条件连接:
WHERE子句中含多个连接条件
3.4.3 嵌套查询
嵌套查询概述
- 一个
SELECT-FROM-WHERE语句称为一个查询块 - 将一个查询块嵌套在另一个查询块的
WHERE子句或HAVING短语的条件中的查询称为嵌套查询
SELECT Sname /*外层查询/父查询*/
FROM Student
WHERE Sno IN (
SELECT Sno /*内层查询/子查询*/
FROM SC
WHERE Cno= ' 2 ');子查询的限制
- 不能使用
ORDER BY子句 - 层层嵌套方式反映了
SQL语言的结构化 - 有些嵌套查询可以用连接运算替代
不相关子查询
- 子查询的查询条件不依赖于父查询
- 由里向外 逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
相关子查询
- 子查询的查询条件依赖于父查询
- 首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表
- 然后再取外层表的下一个元组
- 重复这一过程,直至外层表全部检查完为止
嵌套查询的形式
一、带有IN谓词的子查询
-- 将第一步查询嵌入到第二步查询的条件中 | -- 用自身连接完成:
|
SELECT Sno, Sname, Sdept | SELECT S1.Sno, S1.Sname, S1.Sdept
FROM Student | FROM Student S1, Student S2
WHERE Sdept IN ( | WHERE S1.Sdept = S2.Sdept AND S2.Sname = '刘晨';
SELECT Sdept |
FROM Student |
WHERE Sname= '刘晨' |
); |
|
-- 此查询为不相关子查询。 | 二、带有比较运算符的子查询
[例41]找出每个学生超过他选修课程平均成绩的课程号。
SELECT Sno, Cno
FROM SC x
WHERE Grade >= (
SELECT AVG(Grade)
FROM SC y
WHERE y.Sno = x.Sno
);
此查询为相关子查询。 三、带有ANY(SOME)或ALL谓词的子查询
[例42] 查询其他系中比计算机科学某一学生年龄小的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sage < ANY (
SELECT Sage
FROM Student
WHERE Sdept= ' CS' ) AND Sdept <> 'CS ' ; /*父查询块中的条件 */四、带有EXISTS谓词的子查询
1.EXISTS谓词
- 存在量词∃
- 带有
EXISTS谓词的子查询不返回任何数据,只产生逻辑真值true或逻辑假值false。 - 若内层查询结果非空,则外层的
WHERE子句返回真值 - 若内层查询结果为空,则外层的
WHERE子句返回假值 - 由
EXISTS引出的子查询,其目标列表达式通常都用*,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义
[例44]查询所有选修了1号课程的学生姓名。
思路分析:
本查询涉及Student和SC关系
在Student中依次取每个元组的Sno值,用此值去检查SC关系
若SC中存在这样的元组,其Sno值等于此Student.Sno值,并且其Cno= ‘1’,则取此Student.Sname送入结果关系
用嵌套查询 | 用连接运算
SELECT Sname | SELECT Sname
FROM Student | FROM Student, SC
WHERE EXISTS ( | WHERE Student.Sno=SC.Sno AND SC.Cno= '1';
SELECT * |
FROM SC |
WHERE Sno=Student.Sno AND Cno= '1' |
); |不同形式的查询间的替换
- 一些带
EXISTS或NOT EXISTS谓词的子查询不能被其他形式的子查询等价替换 - 所有带
IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换
用EXISTS/NOT EXISTS实现全称量词(难点)
SQL语言中没有全称量词(For all)- 可以把带有全称量词的谓词转换为等价的带有存在量词的谓词: (\forall x)P ≡\neg (\exists x(\neg P))
[例39]查询与“刘晨”在同一个系学习的学生。
-- 可以用带EXISTS谓词的子查询替换:
SELECT Sno,Sname,Sdept
FROM Student S1
WHERE EXISTS (
SELECT *
FROM Student S2
WHERE S2.Sdept = S1.Sdept AND S2.Sname = '刘晨'
);
[例46] 查询选修了全部课程的学生姓名。
SELECT Sname
FROM Student
WHERE NOT EXISTS (
SELECT *
FROM Course
WHERE NOT EXISTS (
SELECT *
FROM SC
WHERE Sno= Student.Sno AND Cno= Course.Cno
)
);3.4.4 集合查询
集合操作的种类
- 并操作
UNION - 交操作
INTERSECT - 差操作
EXCEPT
参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同
[例48] 查询计算机科学系的学生及年龄不大于19岁的学生。
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;UNION:将多个查询结果合并起来时,系统自动去掉重复元组。
UNION ALL:将多个查询结果合并起来时,保留重复元组
3.4.5 Select语句的一般形式
SELECT [ALL|DISTINCT]
FROM
WHERE
GROUP BY
HAVING
ORDER BY3.5 数据更新
3.5.1 插入数据
两种插入数据方式
- 插入元组
- 插入子查询结果
一、插入元组
INSERT
INTO Student (Sno, Sname, Ssex, Sdept, Sage)
VALUES ('200215128', '陈冬', '男', 'IS', 18);
INSERT
INTO Student
VALUES ('200215126', '张成民', '男', 18, 'CS'); 二、插入子查询结果
INSERT
INTO Dept_age(Sdept,Avg_age)
SELECT Sdept,AVG(Sage)
FROM Student
GROUP BY Sdept;3.5.2 修改数据
UPDATE Student
SET Sage = 22
WHERE Sno= '200215121'; [例7] 将计算机科学系全体学生的成绩置零。
UPDATE SC
SET Grade=0
WHERE 'CS'= (
SELETE Sdept
FROM Student
WHERE Student.Sno = SC.Sno
);
3.5.3 删除数据
[例10] 删除计算机科学系所有学生的选课记录。
DELETE
FROM SC
WHERE 'CS' = (
SELETE Sdept
FROM Student
WHERE Student.Sno=SC.Sno
);3.6 视图
3.6.1 定义视图
- 组成视图的属性列名:全部省略或全部指定
- 子查询不允许含有
ORDER BY子句和DISTINCT短语 WITH CHECK OPTION表示对视图进行UPDATE,INSERT和DELETE操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式)。
CREATE VIEW IS_Student
AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept= 'IS';- 行列子集视图
- 若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,我们称这类视图为行列子集视图。
-- 基于多个基表的视图
[例3] 建立计算机系选修了1号课程的学生视图。
CREATE VIEW CS_S1(Sno, Sname, Grade)
AS
SELECT Student.Sno, Sname, Grade
FROM Student, SC
WHERE Sdept= 'CS' AND Student.Sno=SC.Sno AND SC.Cno= '1';- 基于视图的视图
- 带表达式的视图
- 分组视图
二、删除视图
DROP VIEW <视图名>;3.6.2 查询视图
RDBMS实现视图查询的方法–视图消解法(View Resolution)
- 进行有效性检查
- 转换成等价的对基本表的查询
- 执行修正后的查询
3.6.3 更新视图
- 更新视图是指通过视图来插入(
INSERT)、删除(DELETE)和修改(UPDATE)数据。由于视图是不实际存储数据的虚表,
因此对视图的更新, 最终要转换为对基本表的更新。 - 更新视图的限制:一些视图是不可更新的, 因为对这些视图的更新不能唯一地有意义地转换成对相应基本表的更新