Day4
一.排序
当我们使用普通查询语句的时候可以看到,每次查询出的结果都是相似的
SELECT * FROM employees;
当我们没有使用排序操作,默认查询返回的数据就是按照添加数据的顺序。
1.1排序规则&单列排序
- 使用 ORDER BY 子句排序
- ASC(ascend): 升序(默认是升序)
- DESC(descend):降序
- ORDER BY 子句在SELECT语句的结尾。
# 5.1.1排序规则:ORDER BY(升序,降序)默认升序排列
SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary DESC;
# 使用别名进行排序
SELECT employee_id,salary,salary *12 annua_sal
FROM employees
ORDER BY annua_sal;
注意:
(1)列的别名只能在ORDER BY中使用,不能在WHERE中使用,这和SQL语句执行顺序有关,SQL语句执行时,并不是顺序执行,它先从FROM语句开始执行,在执行WHERE等查询操作,此时无法识别别名,筛选出数据;再执行SELECT操作,筛选出字段,最后再执行ORDER BY操作。
(2)WHERE需要声明在FROM后,ORDER BY前
1.2多列排序
# 5.2 二级排序
SELECT employee_id,salary,department_id
FROM employees
ORDER BY department_id DESC,salary ASC;
可以看出同id下,salary按升序排列
- 可以使用不在SELECT列表中的列排序。
- 在对多列进行排序的时候,首先排序的第一列必须有相同的列值,才会对第二列进行排序。如果第一列数据中所有值都是唯一的,将不再对第二列进行排序。
二.分页
2.1背景
背景1:查询返回的记录太多了,查看起来很不方便,怎么样能够实现分页查询呢?
背景2:表里有 4 条数据,我们只想要显示第 2、3 条数据怎么办呢?
2.2规则
分页原理:所谓分页显示,就是将数据库中的结果集,一段一段显示出来需要的条件。
- 代码:
LIMIT 起始位置偏移量,显示的行数
LIMIT 0,显示行数 = LIMIT 显示行数
# 5.2 分页
# 每页显示二十条记录
SELECT employee_id,last_name
FROM employees
LIMIT 0,20;
# 每页显示二十条记录,第二页
SELECT employee_id,last_name
FROM employees
LIMIT 20,20;
分页显式公式:(当前页数-1)*每页条数,每页条数
SELECT * FROM table
LIMIT(PageNo - 1)*PageSize,PageSize;
5.2.2 WHERE,ORDER BY,LIMIT顺序
# 5.2.2 WHERE,ORDER BY,LIMIT
SELECT employee_id,last_name,salary
FROM employees
WHERE salary>6000
ORDER BY salary DESC
LIMIT 0,10;
注意:
(1)使用 LIMIT 的好处:约束返回结果的数量可以 减少数据表的网络传输量 ,也可以 提升查询效率 。如果我们知道返回结果只有1 条,就可以使用 LIMIT 1 ,告诉 SELECT 语句只需要返回一条记录即可。这样的好处就是 SELECT 不需要扫描完整的表,只需要检索到一条符合条件的记录即可返回。
(2)8.0新特性
# 表中有107条数据,只显示32,33条
# SELECT employee_id,last_name
# FROM employees
# LIMIT 31,2;
# 5.2.3 MySQL8.0新特性:LIMIT 显示条数 OFFSET 起始偏移量
SELECT employee_id
FROM employees
LIMIT 2 OFFSET 31;
(3)在不同的 DBMS 中使用的关键字可能不同。在 MySQL、PostgreSQL、MariaDB 和 SQLite 中使用 LIMIT 关键字,而且需要放到 SELECT 语句的最后面。
三.多表查询
多表查询与子查询都是重点
多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。
前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。比如:员工表和部门表,这两个表依靠“部门编号”进行关联。
1.案例说明
# 6.1 案例引入
# 这里DESC是description(描述)的缩写,可以查看对表的描述(descend降序)
DESC employees;
DESC departments;
DESC locations;
例:查询员工名‘Abel’在哪个城市工作,通过每个表每个表的查,可以查到,但是查询需要三次请求,过于麻烦。
# 查询员工名‘Abel’在哪个城市工作
SELECT *
FROM employees
WHERE last_name = 'Abel';
SELECT *
FROM departments
WHERE department_id = 80;
SELECT *
FROM locations
WHERE location_id = 2500;
解决这个问题有两个思路:
(1)能否把需要查询的这三张表合成为一张表?
会造成数据冗余,导致从磁盘中加载到内存中时间过长,不利于高并发场景。
(2)利用多表查询
使用多表查询
SELECT last_name,employees.department_id,departments.location_id,city,street_address
FROM employees,departments,locations
WHERE last_name = 'Abel'&&employees.department_id = departments.department_id&&departments.location_id = locations.location_id;
2.多表查询
SELECT employee_id,department_name
FROM employees,departments;
查询出了2889条记录,但是员工只有107条记录,发现一个员工对应了很多条部门,查询出现错误,经过分别对employee_id,department_name查询发现employee_id有107条记录,department_name有27条记录,等于说是每个员工都与每个部门匹配了一遍,出现了笛卡尔积的错误。
2.1 笛卡尔积(或交叉连接)的理解
笛卡尔乘积是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中元素个数的乘积数。
SQL92中,笛卡尔积也称为 交叉连接 ,英文是 CROSS JOIN 。在 SQL99 中也是使用 CROSS JOIN表示交叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。在MySQL中如下情况会出现笛卡尔积:
SELECT last_name,department_name
FROM employees,departments;
SELECT last_name,department_name
FROM employees CROSS JOIN departments;
SELECT last_name,department_name
FROM employees INNER JOIN departments;
SELECT last_name,department_name
FROM employees JOIN departments;
- 笛卡尔积的错误会在下面条件下产生:
- 省略多个表的连接条件(或关联条件)
- 连接条件(或关联条件)无效
- 所有表中的所有行互相连接
- 为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。
- 加入连接条件后,查询语法:
SELECT table1.column, table2.column
FROM table1, table2
WHERE table1.column1 = table2.column2; #连接条件
#案例:查询员工的姓名及其部门名称
SELECT last_name, department_name
FROM employees, departments
WHERE employees.department_id = departments.department_id;
2.2 多表查询的正确方式
- 需要有连接
- 在表中有相同列时,在列名之前加上表名前缀。
# 6.2.2 多表查询的正确方式,需要有连接条件
SELECT employee_id,employees.department_id
FROM employees,departments
WHERE employees.department_id = departments.department_id;
总共106条记录,因为有一个人部门ID为NULL,没有查询出来
# 使用表的别名(列的别名不能在WHERE中出现):若果给表起了别名,那么一旦使用表名,必须用别名
SELECT t1.employee_id,t2.department_name,t1.department_id
FROM employees t1,departments t2
WHERE t1.department_id = t2.department_id;
# 查询员工的employee_id last_name department_name city
SELECT employees.employee_id,employees.last_name,departments.department_name,locations.city
FROM employees,departments,locations
WHERE employees.department_id = departments.department_id && departments.location_id = locations.location_id;
注意:
(1)如果给表起了别名,那么一旦使用表名,必须用别名;
(2)要实现n表查询,则至少需要n-1个连接条件;
2.3 多表查询分类讲解
# 6.3.1 针对连接条件:等值连接 & 非等值连接
# 上面的查询都是等值连接
# 非等值连接
SELECT employees.last_name,employees.salary,job_grades.grade_level
FROM employees,job_grades
WHERE employees.salary BETWEEN job_grades.lowest_sal AND job_grades.highest_sal;
前面的不同表之间的连接查询都是非自连接,自己和自己连接查询的为自连接
# 6.3.2 自连接 & 非自连接
# 前面的不同表之间的连接查询都是非自连接,自己和自己连接查询的为自连接
# 查询员工姓名及其ID与其管理者ID姓名
SELECT emp.employee_id,emp.last_name,mgr.employee_id,mgr.last_name
FROM employees emp,employees mgr
WHERE emp.manager_id = mgr.employee_id;
(1)内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行。
(2)外连接:: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。
如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 。
如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表 。
(3)SQL92,SQL99语法规则
- SQL92语法:SQLyog,Navicat不支持SQL92,但是ORCL支持
- 内连接:见上
- 外连接: 使用 ‘ + ’
#左外连接
SELECT employee_id,last_name,department_name
FROM employees,departments
WHERE employees.department_id = departments.department_id(+); #employees.employee_id多一个,所有右表增加
#右外连接
SELECT last_name,department_name
FROM employees ,departments
WHERE employees.department_id(+) = departments.department_id;
- SQL99:使用JOIN…ON子句创建连接的语法结构,既可以处理外连接也可以处理内连接
# SQL99语法标准:
# 内连接:不加INNER默认内连接
SELECT last_name,department_name
FROM employees e INNER JOIN departments d
ON e.department_id = d.department_id;
SELECT last_name,department_name,city
FROM employees e JOIN departments d
ON e.department_id = d.department_id
JOIN locations l
ON d.location_id = l.location_id;
# 外连接
# 左外连接
SELECT last_name,department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.department_id = d.department_id;
# 右外连接
SELECT last_name,department_name
FROM employees e RIGHT OUTER JOIN departments d
ON e.department_id = d.department_id;
左外连接:107条记录
右外连接:122条记录
满外连接:
# 满外连接:MYSQL不支持FULL OUTER JOIN
SELECT last_name,department_name
FROM employees e FULL OUTER JOIN departments d
ON e.department_id = d.department_id;
mysq不支持,ORCL支持
SELECT last_name,department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.department_id = d.department_id
UNION ALL
SELECT last_name,department_name
FROM employees e RIGHT OUTER JOIN departments d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;
UNION操作符
7种JOIN实现
# 6.4 7种join实现
SELECT employee_id,department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id;
SELECT employee_id,department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.department_id = d.department_id;
SELECT employee_id,department_name
FROM employees e RIGHT OUTER JOIN departments d
ON e.department_id = d.department_id;
# 过滤掉中间相同的
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_id IS NULL;
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;
#满外连接另一种写法
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_id IS NULL
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id;
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_id IS NULL
UNION ALL
SELECT last_name,department_name
FROM employees e RIGHT OUTER JOIN departments d
ON e.department_id = d.department_id
WHERE e.department_id IS NULL;
3.SQL99语法新特性
3.1 自然连接
SQL99 在 SQL92 的基础上提供了一些特殊语法,比如 NATURAL JOIN 用来表示自然连接。我们可以把自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中 所有相同的字段 ,然后进行等值连接 。
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
AND e.`manager_id` = d.`manager_id`;
SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;
这两个执行结果相同,自然连接不够灵活。
3.2 USING连接
当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的同名字段进行等值连接。但是只能配合JOIN一起使用。比如:
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id);
不适用于自连接