一、数据定义
关系数据库系统支持三级模式结构,其模式,外模式,内模式中的基本对象有模式、表、视图和索引,所以SQL的数据定义功能包括模式定义、表定义、视图和索引的定义
1. 模式的定义与删除
① 模式定义
1 | create schema 模式名 authorization 用户名; |
示例:
为用户WANG定义一个 学生-课程 模式 S-T
1 | create schema "S-T" authorization WANG; |
定义模式实际上就是定义了一个命名空间,可以在这个空间的基础上进一步定义数据库对象,基本表,视图,索引等
示例:
为用户 ZHANG 创建一个模式 TEST,并且在其中定义一个表 table1
1 | create schema "TEST" authorization ZHANG |
② 删除模式
1 | drop schema 模式名 CASCADE | RESTRICT |
CASCADE | RESTRICT 必选其一
CASCADE
表示删除模式的同时会删除该模式下的所有数据库对象RESTRICT
表示若该模式下存在数据库对象,则拒绝执行删除操作
2. 基本表的定义、删除、修改
数据库的创建和使用:
CREATE DATABASE test;
USE test;
① 定义基本表 CREATE
示例:
1 | CREATE TABLE mytable ( |
SQL标准支持多种数据类型:
② 修改基本表 ALTER
示例:
向Student表中添加入学时间列
1
alter table student add entrance_date DATE;
将年龄的数据类型由字符型转为整数
1
alter table student alter column age INT;
增加课程名称必须取唯一值的约束条件
1
alter table student add unique(cname);
③ 删除基本表
1 | DROP TABLE 表名 [RESTRICT | CASCADE]; |
默认是 RESTRICT
3. 索引的建立和删除
① 建议索引
1 | create [unique][cluster] index 索引名 |
unique 表示此索引的每一个索引值只对应唯一的数据记录
cluster 表示该索引是聚集索引,详见 后序 面试指南 - 索引 章节相关内容
示例:
1 | create unique index sno_index on student(sno); |
② 修改索引
1 | alter index 旧索引名 rename to 新索引名 |
③ 删除索引
1 | drop index 索引名 |
4. 数据字典
数据字典是关系数据库管理系统内部的一组系统表,它记录了数据库中所有的定义信息,包括关系模式定义、视图定义、索引定义、完整性约束定义、各类用户对数据库的操作权限、统计信息等。关系数据库管理系统在执行SQL的数据定义语句时,实际上就是在更新数据字典中的相应信息
二、数据查询
select 语句的一般格式:
以下所有示例全都使用下述三个表
- Student(Sno,Sname, Sage, SDept) 学生表
- Cource (Cno, Cname) 课程表
- SC(Sno,Cno,Grade) 选修表
1. 单表查询
单表查询是指仅涉及一个表的查询
① 查询表中的若干列
查询全体学生的学号和姓名
1 | select Sno, Sname |
目标列表达式 也可以是表达式
1 | select Sname, 2020 - age |
用户可以为查询的列定义别名
1 | select Sname, 2020 - age Birthday |
② 选择表中的若干元组
消除取值重复的行 distinct
使用 distinct 关键字 去除重复记录
1 | select distinct Sno |
查询满足条件的行
使用 where 子句,常用的查询条件如下:
比较
1
2
3select sname
from student
where age <= 20;确定范围
1
2
3
4# 查询年龄在20-33岁之间的学生姓名和年龄
select sname,age
from student
where age between 20 and 33;确定集合
1
2
3
4# 查询计算机系和数据系的学生姓名和性别
select sname,gender
from student
where dept in ('CS','Math');字符匹配
1
2
3
4# 查询姓欧阳且全名为三个汉字的学生的姓名
select sname
from student
where sname like '欧阳_';涉及空值的查询
1
2
3
4# 查询所有有成绩的学生姓名
select sname
from student
where grade is not null;多重条件查询
and 和 or 可用来连接多个查询条件,and 的优先级高于 or,不过可以用 括号来改变优先级
1
2
3
4# 查询计算机系年龄20以下的学生姓名
select sname
from student
where sdept = 'CS' and sage < 20;
③ order by 子句
- desc 降序
- asc 升序 默认
1 | # 院系按升序排,年龄按降序排 |
④ top
1 | # 查询成绩第一的学生姓名 |
1 | # 查询第21-30行的数据,id主键自增,但可能不连续 |
⑤ 聚集函数
函数名 | 功能 |
---|---|
COUNT | 对元组计数 |
TOTAL | 求总和 |
MAX | 求最大值 |
MIN | 求最小值 |
AVG | 求平均值 |
示例:
1 | # 查询学生总人数 |
🚨 起别名 as 可写可不写
⑥ group by 子句
group by 分组:把具有相同的数据值的行放在同一组中。
分组后聚集函数将作用于每一组,即每一组都有一个聚集函数值
示例:
1 | # 求各个课程号及相应的选课人数 |
如果分组后还需要对这些组进行过滤,则使用 HAVING
短语
1 | # 查询选修了三门以上课程的学生学号 |
1 | # 有两个表Study(sno,cno)和Student(sno,sname),查询选修了2或3门课的学生 |
WHERE
过滤行,HAVING
过滤分组,行过滤应当先于分组过滤。
having 与 where 功能、用法相同,执行时机不同。
where 在开始时执行检测数据,对原数据进行过滤。
having 对筛选出的结果再次进行过滤。
having 字段必须是查询出来的,where 字段必须是数据表存在的。
where 不可以使用字段的别名,having 可以。因为执行 WHERE 代码时,可能尚未确定列值。
where 不可以使用聚集函数。一般需用聚集函数才会用 having
SQL标准要求
HAVING 必须引用 GROUP BY 子句中的列或用于合计函数中的列
。
⚠ GROUP BY 子句出现在 WHERE 子句之后,ORDER BY 子句之前
1 | SELECT col, COUNT(*) AS num |
2. 连接查询
若一个查询同时涉及两个以上的表,则称为连接查询
① 等值与非等值连接查询
示例:
1 | # 查序每个学生及选修课的情况 |
② 自身连接
一个表与自己进行连接
示例:
1 | select FIRST.Cno,SECOND.Cpno |
③ 外连接
保存悬浮元组(即不满足条件的元组也保存下来)上一节已经讲过
- OUTER JOIN
- LEFT OUTER JOIN
- RIGHT OUTER JOIN
④ 多表连接
两个以上的表进行连接
1 | # 查询每个学生的学号,姓名,选修的课程名即成绩 |
3. 嵌套查询
在 SQL 语言中,一个 select-from-where 语句称为一个查询块。
将一个查询块套在另一个查询块的 where 子句或 HAVING 短语的条件中的查询称为嵌套查询
① 带有 in 谓词的子查询
1 | # 查找与小明所在同一个系的学生 |
② 带有比较运算符的子查询
1 | # 找出每个学生超过他自己选修课程平均成绩的课程号 |
③ 带有 ANY(SOME)或 ALL 谓词的子查询
子查询返回单值时可以用比较运算符,但返回多值时要用 ANY(有的系统用SOME)或 ALL 谓词修饰符。而使用ANY 或 ALL谓词时必须同时使用比较运算符。
示例:
1 | # 查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄 |
④ 带有 EXISTS 谓词的子查询
EXISTS
代表存在,带有该谓词的子查询不返回任何数据,只产生逻辑真值 true 或逻辑假值 false
exists 引导的内层查询如果 能查出数据,则继续外层查询
not exists 引导的内层查询如果 查不出数据,则继续外层查询
exists 的查询步骤是顺序执行,并不会先做子查询,与 in 相反。
顺序执行,如果exists 的查询结果为真,则将最外层的查询结果添加进最终结果集。对外表进行循环
示例:
1 | # 查询所有选修了1号课程的学生姓名 |
由exists引出的子查询,其目标列表达式通常都用 * ,因为该子查询只返回 true 或 false,给出列名无实际意义
1 | # 查询选修了全部课程的学生姓名 |
由于没有全程量词,可将题目的意思转化为 没有一门课程是他不选修的
exists 可以理解为一个循环
1 | for(循环从Student表拿一行学生数据){ |
1 | # 查询至少选修了学生001选修的全部课程的学生号码 |
翻译为:不存在这样的课程y,001选修了,而学生x没有选修
exists 和 in 的区别:
例如:
select * from A
where id in(select id from B)exists()适合B表比A表数据大的情况
当A表数据与B表数据一样大时, in与exists效率差不多,可任选一个使用.
详细可参考:👉 SQL语句中exists和in的区别
4. 集合查询
select 语句的查询结果是元组的集合,所以多个select语句的结果可进行集合操作。集合操作主要包括
并 UNION
交 INTERSECT
差 EXCEPT
参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同
1 | # 查询计算机系的学生及年龄不大于19的学生 |
5. 基于派生表的查询
子查询不仅可以出现在where子句中,还可以出现在子句中,这时子查询生成的临时派生表成为主查询的查询对象 (必须为派生关系置顶一个别名)
1 | # 找出每个学生超过自己选修课程平均成绩的课程号 |
三、数据更新
1. 插入数据
① 插入元组
1 | insert into Student(Sno,Sname,Sgender,Sdept,Sage) |
若不指出要添加的属性,则需要添加表中的所有属性
② 插入子查询结果
1 | # 对每一个系,求学生的平均年龄,并把结果存入表 Dept_age |
2. 修改数据
① 修改某个元组的值
1 | # 修改学号001的年龄 |
② 修改多个元组的值
1 | # 将所有学生年龄加1岁 |
③ 带子查询的修改语句
1 | # 将计算机系全体学生成绩置0 |
3. 删除数据
① 删除某个元组
1 | # 删除学号001学生记录 |
② 删除多个元组
1 | # 删除所有学生记录 |
③ 带子查询的删除语句
1 | # 删除计算机系所有学生的选课记录 |
1 | # 删除重复数据,只保留一条记录(除id以外,其余全部相同) |
🚨 注意:
1
2
3
4
5 delete from test
where id not in(
select Min(id) from test
group by name
);这样写在 MySQL 中会报错,
You can't specify target table for update in FROM clause
不允许使用同一表中查询的数据作为同一表的更新数据。
我们需要在select外面套上一层,让数据库认为我们不是使用同一个表的查询数据作为更新数据
四、空值的处理
1. 空值的产生
比如:插入语句中没有赋值的属性,其值为空值
1 | insert into Student(Sno,Cno) |
2. 空值的判断
IS NULL / IS NOT NULL
1 | # 查询漏填信息的学生 |
3. 空值的约束条件
属性定义中有 NOT NULL 约束条件时不能取空值
加了 UNIQUE 限制的属性不能取空值
主键不能取空值
五、视图
视图是从一个或几个基本表(或视图)导出的表。
它与基本表不同,是一个虚表。
数据库中只存放视图的定义,不存放视图对应的数据,这些数据任然存放在原来的基本表中。所以一旦基本表中的数据变化,那么视图中的数据也会相应变化。
其实视图就好像一个窗口,透过它可以看到自己想要看到的数据及其变化
1. 建立视图
① 建立在单个表上的视图
1 | # 建立计算机系学生视图,并要求插入/修改/删除操作时,保证该视图只有计算机系学生 |
由于加上了 with check option 子句,以后对视图进行 修改 / 添加 / 删除 操作时,DBMS都会自动加上 Sdept = ‘CS’ 这个条件
若一个视图是从单个基本表导出的,并且只是去掉了某些行某些列,但保留了主键,则称这类视图为 行列子集视图。 上述视图 CS_Student 就是一个行列子集视图
② 建立在多个表上的视图
1 | # 建立计算机系选修了1号课程的学生的视图(包括学号,姓名,成绩) |
由于视图的属性列中包含了两个表的同名列 Sno,所以必须在视图名后面说明视图的各个属性列名
③ 建立在视图上的视图
1 | # 建立计算机系选修了1号课程 且 成绩在90分以上的学生的视图 |
2. 删除视图
1 | drop view 视图名; |
若该视图上还导出了一个视图,则删除视图操作拒绝执行
或者可以使用 CASCADE
进行级联删除,删除该视图和由它导出的所有视图
1 | drop view 视图名 CASCADE; |
3. 查询视图
视图的查询和表的查询是一样的
1 | # 建立计算机系学生视图,并要求插入/修改/删除操作时,保证该视图只有计算机系学生 |
4. 更新视图
更新视图和更新表操作基本一致,不过有些时候视图是不允许更新的
5. 视图的优点
视图能够简化用户的操作
视图使用户能以多种角度看待同一数据
视图对重构数据库提供了一定数据的逻辑独立性
数据的逻辑独立性是指当数据库数据库构造时,如增加新的关系或对原来关系增加新的字段等,用户的应用程序不会受到影响
视图能够对机密数据提供安全保护
适当利用视图可以更清晰的表达查询
6. 视图的缺点
- 查询视图时,必须把对视图的查询转化为对基本表的查询。如果这个视图是由一个复杂的多表查询所定义,那么即使是视图的一个简单查询,数据库也把它变成一个复杂的结合体,需要花费一定的时间。
- 当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改,如果视图涉及多个表的话,由于完整性约束,可能是无法修改的
六、SQL语句综合习题
有如下四个表:
- 供应商表 S(Sno,Sname, Status, City)
- 零件表 P (Pno,Pname,Color,Weight)
- 工程项目表 J (Jno,Jname,City)
- 供应情况表 SPJ (Sno,Pno,Jno,Qty)
找出所有供应商姓名和所在城市
1
2select Sname,City
from S;找出所有零件的名称、颜色、重量
1
2select Pname,Color,Weight
from P;找出使用供应商S1所供应零件的工程号码
1
2
3select distinct Jno
from SPJ
where Sno = 'S1';找出工程项目J2使用的各种零件的名称及其数量
1
2
3
4select P.Pname,SPJ.QTY
from SPJ,P
where SPJ.Pno = P.Pno and
SPJ.Jno = 'J2';找出上海厂商供应的所有零件号码
1
2
3
4select Pno
from SPJ,S
where SPJ.Sno = S.Sno and
S.City = '上海';找出使用上海产的零件的工程名称
1
2
3
4
5select Jname
from SPJ,S,J
where S.Sno = SPJ.Sno and
J.Jno = SPJ.Jno and
S.City = '上海';找出没有使用天津产的零件的工程号码
1
2
3
4
5
6
7
8select distinct Jno
from SPJ
where Jno not in(
select distinct Jno
from SPJ,S
where SPJ.Sno = S.Sno and
S.City = '天津'
);把全部红色零件的颜色改成蓝色
1
2
3update P
set Color = '蓝色'
where Color = '红色';由S5供给J4的零件P6改为由S3供应
1
2
3
4
5Update SPJ
set Sno = 'S3'
where Sno = 'S5' and
Jno = 'J4' and
Pno = 'P6';从供应商中删除供应商号是S2的记录,并从供应关系中删除相应的记录
1
2
3
4
5delete from S
where Sno = 'S2';
delete from SPJ
where Sno = 'S2';请将(S2,J6,P4,200)插入供应情况关系
1
2insert into SPJ
values(S2,J6,P4,200);