第3章 关系数据库标准语言SQL
SQL(Structed Query Language)是关系数据库的标准语言,它包含了关系代数的运算,并进行了扩充
1. SQL概述
1.1 SQL的组成
1.1.1 操作对象
- 表和视图是SQL的操作对象
- 表就是关系模型的关系。表由名称、结构(关系模式)和数据3部分组成。表的名称和结构存储在DBMS的数据字典,表的数据保存在数据库
- 视图时一个特殊的表,基本上可以把它当作表使用
1.1.2 操作分类
1. 数据定义语言(DDL)
- 数据定义语言(DDL)
- 定义数据库的逻辑结构,包括定义表、视图和索引
- 数据定义语言只是定义结构,不涉及具体的数据
- 数据定义语句的执行结果会保存在数据字典
[] 中里面的内容意味着可写可不写
查询所有数据库:
SHOW DATABASES;
查询当前数据库:
SELECT DATABASE();
创建数据库:
CREATE DATABASE [ IF NOT EXISTS ] 数据库名 [ DEFAULT CHARSET 字符集] [COLLATE 排序规则 ];
删除数据库:
DROP DATABASE [ IF EXISTS ] 数据库名;
使用数据库:
USE 数据库名;
注意事项: UTF8字符集长度为3字节,有些符号占4字节,所以推荐用utf8mb4字符集 即:
create database if not exists itheima default charset utf8mb4;
查询当前数据库所有表:
SHOW TABLES;
查询表结构:
DESC 表名;
查询指定表的建表语句:
SHOW CREATE TABLE 表名;
创建表:
CREATE TABLE 表名(
字段1 字段1类型 [COMMENT 字段1注释],
字段2 字段2类型 [COMMENT 字段2注释],
字段3 字段3类型 [COMMENT 字段3注释],
...
字段n 字段n类型 [COMMENT 字段n注释]
)[ COMMENT 表注释 ];
最后一个字段后面没有逗号


修改表
添加字段:
ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];
例:ALTER TABLE emp ADD nickname varchar(20) COMMENT '昵称';
修改数据类型:
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
修改字段名和字段类型:
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
例:将emp表的nickname字段修改为username,类型为varchar(30)
ALTER TABLE emp CHANGE nickname username varchar(30) COMMENT '昵称';
删除字段:
ALTER TABLE 表名 DROP 字段名;
修改表名:
ALTER TABLE 表名 RENAME TO 新表名
删除表:
DROP TABLE [IF EXISTS] 表名;
删除表,并重新创建该表(清空数据):
TRUNCATE TABLE 表名;
MySQL图形化界面: Navicat, Sqlyog, DataGrip

2. 数据操纵语言(DML)
- 数据操纵语言(DML)
- 包括查询和更新两大类操作
- 查询包括选择、投影、连接等运算
- 更新包括插入、删除和修改操作
INSERT, DELETE, UPDATE
- 添加数据
定字段:
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...);
全部字段:
INSERT INTO 表名 VALUES (值1, 值2, ...);
批量添加数据:
INSERT INTO 表名 (字段名1, 字段名2, ...) VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, 值2, ...);
INSERT INTO 表名 VALUES (值1, 值2, ...), (值1, 值2, ...), (值1, 值2, ...);
注意事项:
字符串和日期类型数据应该包含在引号中
插入的数据大小应该在字段的规定范围内
- 更新和删除数据
修改数据:
UPDATE 表名 SET 字段名1 = 值1, 字段名2 = 值2, ... [ WHERE 条件 ];
例:
UPDATE emp SET name = 'Jack' WHERE id = 1;
删除数据:
DELETE FROM 表名 [ WHERE 条件 ];
* DELETE语句不能删除某一个字段的值(可以使用UPDATE)
3. 数据查询语言(DQL)
-
数据查询语言(DQL, Data Query Language), 用来查询数据库中表的记录
-
语法
SELECT
字段列表
FROM
表名字段
WHERE
条件列表
GROUP BY
分组字段列表
HAVING
分组后的条件列表
ORDER BY
排序字段列表
LIMIT
分页参数
- 基础查询
查询多个字段:
SELECT 字段1, 字段2, 字段3, ... FROM 表名;
SELECT * FROM 表名;
设置别名:
SELECT 字段1 [ AS 别名1 ], 字段2 [ AS 别名2 ], 字段3 [ AS 别名3 ], ... FROM 表名;
SELECT 字段1 [ 别名1 ], 字段2 [ 别名2 ], 字段3 [ 别名3 ], ... FROM 表名;
去除重复记录:
SELECT DISTINCT 字段列表 FROM 表名;
-
条件查询
语法:
SELECT 字段列表 FROM 表名 WHERE 条件列表;

-
聚合查询
聚合查询(聚合函数)
语法:SELECT 聚合函数(字段列表) FROM 表名;
常见聚合函数:
函数 功能
count 统计数量
max 最大值
min 最小值
avg 平均值
sum 求和
NULL值不参与所有聚合函数运算
- 分组查询
语法:SELECT 字段列表 FROM 表名 [ WHERE 条件 ] GROUP BY 分组字段名 [ HAVING 分组后的过滤条件 ];
where 和 having 的区别:
执行时机不同:where是分组之前进行过滤,不满足where条件不参与分组;having是分组后对结果进行过滤。
判断条件不同:where不能对聚合函数进行判断,而having可以。
注意事项:
- 执行顺序:where > 聚合函数 > having
- 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义
- 排序查询语法:
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2;
排序方式:ASC: 升序(默认)DESC: 降序
注意事项: 如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序
- 分页查询语法:
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数;
例子:
-- 查询第一页数据,展示10条
SELECT * FROM employee LIMIT 0, 10;
-- 查询第二页
SELECT * FROM employee LIMIT 10, 10;
<font color=red>注意事项:
起始索引从0开始,起始索引 = (查询页码 - 1) * 每页显示记录数
分页查询是数据库的方言,不同数据库有不同实现,MySQL是LIMIT
如果查询的是第一页数据,起始索引可以省略,直接简写 LIMIT 10 </font>
- DQL执行顺序: FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT
4. 数据控制语言(DCL)
- 数据控制语言(DCL)
- 包括对关系和视图的访问权限的描述,以及对事务的控制语句。
- 嵌入式SQL和动态SQL(Embeded SQL and Dynamic SQL )
- 规定了在诸如C、Fortran、Cobol等宿主语言使用SQL的规则
- 管理用户
查询用户:
USE mysql;
SELECT * FROM user;
创建用户:
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
修改用户密码:
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
删除用户:
DROP USER '用户名'@'主机名';
例子:
-- 创建用户test,只能在当前主机localhost访问
create user 'test'@'localhost' identified by '123456';
-- 创建用户test,能在任意主机访问
create user 'test'@'%' identified by '123456';
create user 'test' identified by '123456';
-- 修改密码
alter user 'test'@'localhost' identified with mysql_native_password by '1234';
-- 删除用户
drop user 'test'@'localhost';
- 权限控制
查询权限:
SHOW GRANTS FOR '用户名'@'主机名';
授予权限:
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
撤销权限:
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
注意事项:
* 多个权限用逗号分隔
* 授权时,数据库名和表名可以用 * 进行通配,代表所有
1.2 SQL特点
- 综合统一
- SQL集数据定义语言、数据操纵语言、数据控制语言的功能于一身,语言风格统一,操作符统一,查询、插入、删除、更新等操作都只需一种操作符
- 高度非过程化
- 只要提出“做什么”,而无须指明“怎么做”。“怎么做”由系统自动完成。用户是在数据库的逻辑结构(关系模型)层次上使用数据库,无须了解数据库的物理结构
- 面向集合的操作方式
- 操作对象、操作结果都是关系。SQL采用集合操作方式
- 以同一种语法结构提供两种使用方式
- SQL语句能够嵌入高级语言(如C、Cobol、Fortran)
- 语言简洁,易学易用
- 核心概念9个动词

2. 数据类型和表的定义
- SQL使用表(Table)指代关系模型的关系,使用列(Column)指代属性
2.1 数据类型
- SQL:1999标准定义了3种数据类型:预定义数据类型、构造类型、用户自定义类型
2.1.1 预定义数据类型
2.1.1.1 串
- 串分为字符串、字节串(8bit)、位串(单bit)

2.1.1.2 数字
- 数字有精确数值和近似数值

2.1.1.3 布尔类型
- 布尔运算也可能产生unknown值,一般用空值代表
2.1.1.4 日期时间和区间(Datetime and interval)

2.2 表的定义
2.2.1 定义表
- SQL使用CREATE TABLE语句定义表

2.2.1.1 实体完整性



2.2.1.2 参照完整性


-
参照完整性违约处理
(1) 拒绝(NO ACTION)执行
不允许该操作执行。该策略一般设置为默认策略(2)瀑布删除(CASCADE)操作
当删除或修改被参照表(Student)的一个元组造成了与参照表(SC)的不一致,则删除或修改参照表中的所有造成不一致的元组(3)设置为空值(SET-NULL)
当删除或修改被参照表的一个元组时造成了不一致,则将参照表中的所有造成不一致的元组的对应属性设置为空值。
2.2.1.3 列值完整性

2.2.1.4 用户自定义完整性
- 用户定义的完整性是:针对某一具体应用的数据必须满足的语义要求
- 可分为两类:
- 属性上的约束条件
- 元组上的约束条件
- 属性上的约束条件
-
CREATE TABLE时定义属性上的约束条件
列值非空(NOT NULL)
列值唯一(UNIQUE)
检查列值是否满足一个条件表达式(CHECK)

- 元组上约束条件
-
在CREATE TABLE时可以用CHECK短语定义元组上的约束条件,即元组级的限制
-
同属性值限制相比,元组级的限制可以设置不同属性之间的取值的相互约束条件

2.2.2 修改表的定义
-
SQL用ALTER TABLE语句修改表,许多DBMS有独自的格式,其一般格式为:
ALTER TABLE <表名>
[ADD <新列名> <数据类型描述符> [完整性]]
[DROP <完整性名>]
[MODIFY <列名> <数据类型描述符>];


2.2.3 数据查询
- 查询是指从数据库中找到感兴趣的数据。SQL的SELECT语句用于查询,它集成了关系代数的选择、投影、连接以及集合运算并增加了分组、排序等功能
2.2.3.1 SELECT语句
SELECT [ALL|DISTINCT] <目标列表达式> [别名] [, <目标列表达式> [别名] …]
FROM <表名或视图名> [别名] [,<表名或视图名> [别名] …]
[WHERE <条件表达式>]
[GROUP BY <列名表> [HAVING <条件表达式>]]
[ORDER BY <列名> [ASC|DESC][, <列名> [ASC|DESC]];
*代表全部的列(次序同CREATE),SELECT *



2.2.3.2 DISTINCT
-
集合不允许有重复的元素
允许有重复的元素的集合叫做包
SELECT的默认结果是包
-
DISTINCT 去除重复的行,将包变换成集合
DISTICT 必须在SELECT之后,第1个列之前
只能有1个DISTICT
比如:SELECT DISTINCT Sdept







2.2.3.4 ORDEY BY

2.2.4 聚集函数
- 聚集函数接受一个集合(包),返回一个值
- COUNT([DISTINCT|ALL] * ) 统计元组数
- COUNT([DISTINCT|ALL] <列名>) 统计某列的值的数量
- SUM([DISTINCT|ALL] <列名>) 计算某列的值的总和
- AVG([DISTINCT|ALL] <列名>) 计算某列的平均值
- MAX([DISTINCT|ALL] <列名>) 求某列的最大值
- MIN([DISTINCT|ALL] <列名>) 求某列的最小值


- 聚集函数自动去除NULL
2.2.5 GROUP BY
- 用于分组,分组列
- 在分组列上有相同值的元组组成了一个分组
- GROUP BY 列名, ..., 列名


2.2.6 HAVING
- 选择符合条件的分组:HAVING <条件表达式>


3. 多表查询
- 从概念上讲,FROM子句先对这些表做笛卡儿积运算,得到一个临时表,之后的选择、投影等运算都是针对这个临时表进行,从而将多表查询转换为单表查询。
3.1 内连接查询
- 内连接查询的是两张表交集的部分
隐式内连接:
SELECT 字段列表 FROM 表1, 表2 WHERE 条件 ...;
显式内连接:
SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ...;
显式性能比隐式高
3.2 外连接查询
左外连接:
查询左表所有数据,以及两张表交集部分数据
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ...;
相当于查询表1的所有数据,包含表1和表2交集部分数据
右外连接:
查询右表所有数据,以及两张表交集部分数据
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ...;
3.3 自连接查询
-
当前表与自身的连接查询,自连接必须使用表别名
-
语法:
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ...; -
自连接查询,可以是内连接查询,也可以是外连接查询
3.4 联合查询 union, union all
- 把多次查询的结果合并,形成一个新的查询集
SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...
- 注意事项
- UNION ALL 会有重复结果,UNION 不会
- 联合查询比使用or效率高,不会使索引失效














4. 集合运算


5. 子查询
- 包含子查询的查询叫做嵌套查询,嵌套查询分为相关嵌套查询和不相关嵌套查询
5.1 定义
-
SQL语句中嵌套SELECT语句,称谓嵌套查询,又称子查询。
-
SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2);
-
子查询外部的语句可以是 INSERT / UPDATE / DELETE / SELECT 的任何一个
-
根据子查询结果可以分为:
- 标量子查询(子查询结果为单个值)
- 列子查询(子查询结果为一列)
- 行子查询(子查询结果为一行)
- 表子查询(子查询结果为多行多列)
-
根据子查询位置可分为:
- WHERE 之后
- FROM 之后
- SELECT 之后
5.2 标量子查询
- 子查询返回的结果是单个值(数字、字符串、日期等)。
- 常用操作符:= <> > >= < <=
-- 查询销售部所有员工
select id from dept where name = '销售部';
-- 根据销售部部门ID,查询员工信息
select * from employee where dept = 4;
-- 合并(子查询)
select * from employee where dept = (select id from dept where name = '销售部');
-- 查询xxx入职之后的员工信息
select * from employee where entrydate > (select entrydate from employee where name = 'xxx');
5.3 列子查询
-
返回的结果是一列(可以是多行)。
-
常用操作符:

-- 查询销售部和市场部的所有员工信息
select * from employee where dept in (select id from dept where name = '销售部' or name = '市场部');
-- 查询比财务部所有人工资都高的员工信息
select * from employee where salary > all(select salary from employee where dept = (select id from dept where name = '财务部'));
-- 查询比研发部任意一人工资高的员工信息
select * from employee where salary > any (select salary from employee where dept = (select id from dept where name = '研发部'));
5.4 行子查询
- 返回的结果是一行(可以是多列)。
- 常用操作符:=, <>, IN, NOT IN
-- 查询与xxx的薪资及直属领导相同的员工信息
select * from employee where (salary, manager) = (12500, 1);
select * from employee where (salary, manager) = (select salary, manager from employee where name = 'xxx');
5.4 表子查询
- 返回的结果是多行多列, 常用操作符:IN
-- 查询与xxx1,xxx2的职位和薪资相同的员工
select * from employee where (job, salary) in (select job, salary from employee where name = 'xxx1' or name = 'xxx2');
-- 查询入职日期是2006-01-01之后的员工,及其部门信息
select e.*, d.* from (select * from employee where entrydate > '2006-01-01') as e left join dept as d on e.dept = d.id;
5.1 WHERE子句中的子查询
5.1.1 比较运算符
子查询的结果是元组的集合,即一个表。如果子查询的结果是一个单列并且单行的表,则可以作为比较运算符的运算对象

5.1.1.1 SOME和ALL




-
相关嵌套查询,因为子查询有一个变量x,当未确定x的值时,无法得到查询的结果,而x代表父查询的元组,与父查询相关。
-
不相关嵌套查询的子查询先于父查询执行,并且只需要执行一次,而相关嵌套查询对父查询的每个元组都要执行一次子查询


5.1.2 谓词IN
-
谓词IN是二元运算符,一般书写形式为A IN S,A是一个列名,S是一个集合



本查询也可以利用连接运算实现SELECT Student.Sno, Sname
FROM Student, SC, Course
WHERE Studenet.Sno = SC.Sno AND
SC.Cno = Course.Cno AND
Course.Cname = '管理学';
5.1.3 谓词EXISTS
- 谓词EXISTS是一元运算符,运算数是一个集合,如果该集合不是空集,则运算结果为真,否则为假


使用EXCEPT运算符和谓词EXISTS的SQL语句为:

使用谓词IN和EXISTS的SQL语句为:

只使用谓词EXISTS的SQL语句为:




5.2 FROM子句中的子查询
- FROM子句指定查询要使用的表,一般情况下,这些表是数据库中实际存在的表。如示例数据数据库的Student、Course和SC表。
- 子查询的结果是一个表,但只是一个中间结果,并没有存放在数据库。
- 为了在 FROM 子句使用子查询,要给子查询生成的临时表命名,有时还要命名临时表的列。





5.3 外连接
-
为了解决参与连接的表的某些元组没有出现在连接结果中的问题,需要使用左外连接、右外连接和全外连接运算。作为区分,前面介绍的连接叫做内连接
-
*= 代表左外连接,单新版本不再支持
-
A {FULL | LEFT | RiGHT} OUTER JOIN B ON Condition
关键字JOIN的左、右是参与连接的表名,ON是连接条件,OUTER代表外连接运算
5.3.1 左外连接运算







5.3.2 右外连接运算

6. 数据更新
- 数据更新操作有3个:向表插入数据、修改表的数据、删除表的数据
6.1 插入操作
-
INSERT
INTO <表名> [(<列1>[, <列2>…])
VALUES (<常量1> [, <常量2>]…);
-
INSERT
INTO <表名> [(<属性列1> [, <属性列2>…])
查询;


6.2 修改操作
-
修改操作又称为更新操作
-
UPDATE <表名>
SET <列名>=<表达式>[, <列名>=<表达式>]…
[WHERE <条件>];


6.3 删除操作
-
DELETE
FROM <表名>
[WHERE <条件>];
例3.71 删除学号为2000012的学生的记录。
DELETE
FROM Student
WHERE Sno='2000012';

7. 视图
7.1 视图的定义
- 一个SELECT 语句(的查询结果)
- 虚表,数据库管理系统只存储视图的定义(SELECT语句) ,而不存放视图的数据
- 使用视图时,进行视图消隐,获取数据。
- 更新操作受到一些限制。
7.2 建立视图
CREATE VIEW <视图名>[(<列名>[, <列名>]…)]
AS <查询>
[WITH CHECK OPTION];



7.3 删除视图
-
DROP VIEW <视图名>
例3.78 删除视图Student_CS。DROP VIEW Student_CS;
-
执行DROP VIEW语句后,DBMS从数据字典中删除视图Student_CS的定义
7.4 查询视图

8. 索引
8.1 索引的概念
-
索引是一个独立的、物理的数据库结构
-
基于表的一列或多列建立,按照列值排序。
-
索引不是关系模型的概念,它属于物理实现的范畴
-
在关系上是否建立索引、建立什么样的索引要慎重考虑。因为索引虽然加快了查询速度,但维护索引也要付出代价。
-
索引一般由DBA建立
-
索引为查询的实现提供了更多的选择
-
执行一个查询时,由DBMS的查询优化子系统决定是否使用索引、
-
使用哪个索引,而用户无权干预
-
按照索引列上的值是否唯一:
唯一索引(UNIQUE)
非唯一索引(NOT UNIQUE) -
按照索引的结构:
- 聚簇索引(Clustered Index)
聚簇索引要求表中元组的存放次序和索引中索引项的存放次序相同,或者说表中的元组也是有序的,非聚簇索引则无此要求。
由于表中的元组只能有一种物理存储顺序,因此一个表最多有一个聚簇索引。表的数据发生变化后,为了维护表的元组的有序性,要付出很大的代价。
- 非聚簇索引(Nonclustered Index)
8.2 建立、删除索引


9. 存取控制
9.1 授权
-
SQL使用GRANT语句向用户授予操作权限
GRANT <权限>[,<权限>…]
[ON <表名或视图名>]
TO <用户>[,<用户>…]
[WITH GRANT OPTION];



9.2 收回权限

9.3 角色

9.4 其他权限

10. 空值的处理
- 构成主码的列不能取空值,有NOT NULL限制的列不能取空值
- 空值与另一个值(包括另一个空值)的算术运算的结果为空值
- 空值与另一个值(包括另一个空值)的比较运算的结果为UNKNOWN
- 有了UNKNOWN后,传统的二值(TRUE、FALSE)逻辑就变成了三值逻辑
- 只有使WHERE和HAVING子句的选择条件为TRUE的元组,才会被选中
- 聚集函数除了COUNT(*)外,自动去除空值



11. 函数
11.1 字符串函数

11.2 数值函数

11.3 日期函数

11.4 流程函数

12. 约束
- 约束概念: 约束是作用于表中字段上的规则, 用于限制存储在表中的数据
- 目的: 保证数据库中数据的正确, 有效性和完整性
- 约束是作用于表中字段上的,可以再创建表/修改表的时候添加约束。

create table user(
id int primary key auto_increment,
name varchar(10) not null unique,
age int check(age > 0 and age < 120),
status char(1) default '1',
gender char(1)
);
- 外键约束: 外键用来让两张表的数据之间建立连接, 从而保证数据的一致性和完整性
添加外键:
CREATE TABLE 表名(
字段名 字段类型,
...
[CONSTRAINT] [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名)
);
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表(主表列名);
-- 例子
alter table emp add constraint fk_emp_dept_id foreign key(dept_id) references dept(id);
删除外键:
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;

ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名(主表字段名) ON UPDATE 行为 ON DELETE 行为;

浙公网安备 33010602011771号