【MySQL】-【排序】-【分页】-【多表查询】

排序数据

一、排序规则:使用ORDER BY对查询到的数据进行排序操作。

  1. 升序:ASC(默认)
  2. 降序:DESC

二、ORDER BY子句在SELECT语句的结尾。

# 练习:按照salary从高到低的顺序显示员工信息
SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary DESC;

# 练习:按照salary从低到高的顺序显示员工信息
SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary ASC;

SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary; # 如果在ORDER BY 后没有显式指名排序的方式的话,则默认按照升序排列。

#2. 我们可以使用列的别名,进行排序
SELECT employee_id,salary,salary * 12 annual_sal
FROM employees
ORDER BY annual_sal;

#列的别名只能在 ORDER BY 中使用,不能在WHERE中使用。
#如下操作报错!
SELECT employee_id,salary,salary * 12 annual_sal
FROM employees
WHERE annual_sal > 81600;

#3. 强调格式:WHERE 需要声明在FROM后,ORDER BY之前。
# 排序字段可以和查询字段不一样
# 查询语句在查询时不是按照从上到下查询的,而是先找到表(FROM employees),
# 再对表进行过滤(WHERE department_id IN (50,60,70)),然后查询(SELECT employee_id,salary),
# 最后排序(ORDER BY department_id DESC;)
SELECT employee_id,salary
FROM employees
WHERE department_id IN (50,60,70)
ORDER BY department_id DESC;

#4. 二级排序
#练习:显示员工信息,按照department_id的降序排列,针对department_id相同的员工,按照salary的升序排列
SELECT employee_id,salary,department_id
FROM employees
ORDER BY department_id DESC,salary ASC;

分页

一、mysql使用limit实现数据的分页显示
二、格式:LIMIT [位置偏移量,] 行数。第一个“位置偏移量”参数指示MySQL从哪一行开始显示,是一个可选参数,如果不指定“位置偏移量”,将会从表中的第一条记录开始(第一条记录的位置偏移量是0,第二条记录的位置偏移量是1,以此类推);第二个参数“行数”指示返回的记录条数。

# 需求1:每页显示20条记录,此时显示第1页
SELECT employee_id,last_name
FROM employees
LIMIT 0,20;

# 需求2:每页显示20条记录,此时显示第2页
SELECT employee_id,last_name
FROM employees
LIMIT 20,20;

# 需求3:每页显示20条记录,此时显示第3页
SELECT employee_id,last_name
FROM employees
LIMIT 40,20;

#需求:每页显示pageSize条记录,此时显示第pageNo页:
#公式:LIMIT (pageNo-1) * pageSize,pageSize;

#2.2 WHERE ... ORDER BY ...LIMIT 声明顺序如下:
#一般ORDER BY ...LIMIT都放在最后,且LIMIT垫底

# LIMIT的格式: 严格来说:LIMIT 位置偏移量,条目数
# 结构"LIMIT 0,条目数" 等价于 "LIMIT 条目数"

SELECT employee_id,last_name,salary
FROM employees
WHERE salary > 6000
ORDER BY salary DESC
#limit 0,10;
LIMIT 10;

#练习:表里有107条数据,我们只想要显示第 32、33 条数据怎么办呢?
SELECT employee_id,last_name
FROM employees
LIMIT 31,2;

#2.3 MySQL8.0新特性:LIMIT ... OFFSET ...
#LIMIT 行数 OFFSET 偏移量
#练习:表里有107条数据,我们只想要显示第 32、33 条数据怎么办呢?
SELECT employee_id,last_name
FROM employees
LIMIT 2 OFFSET 31;

#练习:查询员工表中工资最高的员工信息
SELECT employee_id,last_name,salary
FROM employees
ORDER BY salary DESC
#limit 0,1
LIMIT 1;

#2.4 LIMIT 可以使用在MySQL、PGSQL、MariaDB、SQLite 等数据库中使用,表示分页。
# 不能使用在SQL Server、DB2、Oracle!

多表查询

一、多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。
二、这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。比如:员工表和部门表,这两个表依靠“部门编号”进行关联。
在这里插入图片描述
三、假如没有多表查询,我们想查询员工名为’Abel’的人在哪个城市工作,需要先去员工表中查询’Abel’的信息,发现他在80部门,然后去部门表中查询80部门的信息,知道了80部门所在位置的代码是2500,然后再去locations表中查询代码是2500的地址:

SELECT * 
FROM employees
WHERE last_name = 'Abel';

SELECT *
FROM departments
WHERE department_id = 80;

SELECT *
FROM locations 
WHERE location_id = 2500;

四、利用多表查询查询员工的姓名及其部门名称:

SELECT last_name, department_name
FROM employees, departments;

查询出2889条记录,分别查询employees和departments发现每个员工都与每个部门匹配了一遍,我们把这种情况称为笛卡尔积错误。

SELECT *
FROM employees;  #107条记录

SELECT 2889 / 107
FROM DUAL;# 27

SELECT *
FROM departments; # 27条记录

五、SQL92中,笛卡尔积也称为交叉连接 ,英文是CROSS JOIN。在 SQL99中也是使用CROSS JOIN表示交叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。在MySQL中如下情况会出现笛卡尔积:

SELECT employee_id,department_name
FROM employees CROSS JOIN departments;#查询出2889条记录

六、笛卡尔积的错误会在下面条件下产生:

  1. 省略多个表的连接条件(或关联条件)
  2. 连接条件(或关联条件)无效
  3. 所有表中的所有行互相连接

七、为了避免笛卡尔积, 可以在WHERE加入有效的连接条件,格式:

SELECT 列名1, 列名2
FROM1,2
WHERE1.列名1 =2.列名2; #连接条件

上述查询代码改为:

SELECT employee_id,department_name
FROM employees,departments
#两个表的连接条件
WHERE employees.`department_id` = departments.department_id;

八、如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表,比如我们要查department_id这个字段,这个字段是employees和departments关联的字段,两个表都有,所以此时我们需要指明到底是查哪个表的department_id

SELECT employee_id,department_name,employees.department_id
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;

九、从sql优化的角度,建议多表查询时,每个字段前都指明其所在的表,所以上述代码建议写为:

SELECT employees.employee_id,departments.department_name,employees.department_id
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;

十、可以给表起别名,在SELECTWHERE中使用表的别名。

SELECT emp.employee_id,dept.department_name,emp.department_id
FROM employees emp,departments dept
WHERE emp.`department_id` = dept.department_id;

如果给表起了别名,一旦在SELECTWHERE中使用表名的话,则必须使用表的别名,而不能再使用表的原名,这是因为代码执行时,先执行FROM employees emp,departments dept,他知道你给表起了别名就用别名覆盖了原来的表名,以后他只认识别名。如下的操作是错误的:

SELECT emp.employee_id,departments.department_name,emp.department_id
FROM employees emp,departments dept
WHERE emp.`department_id` = departments.department_id;

十一、如果有n个表实现多表的查询,则需要至少n-1个连接条件,且每个连接条件用AND连接。例如查询员工的employee_idlast_namedepartment_namecity

SELECT e.employee_id,e.last_name,d.department_name,l.city,e.department_id,l.location_id
FROM employees e,departments d,locations l
WHERE e.`department_id` = d.`department_id`
AND d.`location_id` = l.`location_id`;

十二、多表查询的分类

  1. 角度1:等值连接 vs 非等值连接
  2. 角度2:自连接 vs 非自连接
  3. 角度3:内连接 vs 外连接

非等值连接

一、我们前面讲的所有都是等值连接,连接条件中用=连接两个表的字段:WHERE emp.department_id = dept.department_id;,不用=连接的就是非等值连接
二、现在我们要查询员工的薪资处于哪个级别,代码如下:
在这里插入图片描述

SELECT e.last_name,e.salary,j.grade_level
FROM employees e,job_grades j
#where e.`salary` between j.`lowest_sal` and j.`highest_sal`;
WHERE e.`salary` >= j.`lowest_sal` AND e.`salary` <= j.`highest_sal`;

自连接

一、自连接:
在这里插入图片描述
二、假如我想查询employees表中的员工id,员工姓名及其管理者的id和姓名,那么我需要用取别名的方式将employees表虚拟成两张表以代表不同的意义,然后两个表再进行内连接,外连接等查询:

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`;

内连接

一、内连接:合并具有同一列的两个以上的表的行,结果集中不包含一个表与另一个表不匹配的行。也就是说我们只把满足查询条件的数据查出来了,其他的数据没有要

SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id;  #只有106条记录

二、外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时,结果表中相应的列为空(NULL)。也就是说外连接就是把不满足条件的数据也查出来了,如果把左表中不满足条件的查出来了就叫左外连接,如果把右表中不满足条件的查出来了,就叫右外连接,如果左右表中不满足条件的都被查出来了,就叫满连接

  1. 如果是左外连接,则连接条件中左边的表也称为主表 ,右边的表称为从表 。
  2. 如果是右外连接,则连接条件中右边的表也称为主表 ,左边的表称为从表 。

SQL92语法实现内连接:见上,略

SQL92语法实现外连接:

一、在SQL92中采用(+)代表从表所在的位置。即左或右外连接中,(+)表示哪个是从表。
二、在SQL92中,只有左外连接和右外连接,没有满(或全)外连接。
三、MySQL不支持SQL92语法中外连接的写法!Oracle支持

#不支持:
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id(+);

在数据少的那个表后面写(+)

SQL99语法实现多表查询

一、SQL99语法中使用JOIN ...ON的方式实现多表的查询。这种方式也能解决外连接的问题。MySQL是支持此种方式的。

SELECT table1.column, table2.column,table3.column
FROM table1 
JOIN table2 ON table1 和 table2 的连接条件
JOIN table3 ON table2 和 table3 的连接条件

说明:

  1. 关键字JOININNER JOINCROSS JOIN一样,都用来内连接
  2. 可以使用ON子句指定额外的连接条件。
  3. 这个连接条件是与其它条件分开的。
#SQL99语法实现内连接:
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`;

二、SQL99语法实现外连接:

#练习:查询所有的员工的last_name,department_name信息 
# 左外连接:
SELECT last_name,department_name
FROM employees e LEFT 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`;

LEFT JOIN等同于LEFT OUTER JOIN
RIGHT JOIN等同于RIGHT OUTER JOIN
MySQL不支持满外连接FULL JOIN,但是可以用LEFT JOIN UNION RIGHT JOIN代替

UNION的使用

合并查询结果利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNIONUNION ALL关键字分隔。

SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2

说明:

  1. UNION操作符返回两个查询的结果集的并集,去除重复记录。
  2. UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。
  3. 执行UNION ALL语句时所需要的资源比UNION语句少,因为UNION ALL会对合并结果去重。如果明确知道合并数据后的结果数据不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效率。

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 JOIN departments d
ON e.`department_id` = d.`department_id`;

# 右上图:右外连接
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;

# 右中图:
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;


# 左下图:满外连接
# 方式1:左上图 UNION ALL 右中图

SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
UNION ALL
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;


# 方式2:左中图 UNION ALL 右上图

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`;

# 右下图:左中图  UNION ALL 右中图
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`
WHERE e.`department_id` IS NULL;

SQL99语法新特性

自然连接

NATURAL JOIN:我们可以把自然连接理解为SQL92中的等值连接。它会帮你自动查询两张连接表中所有相同的字段 ,然后进行等值连接 :

SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;

等同于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`;

USING连接

一、可以使用USING指定数据表里的同名字段进行等值连接。但是只能配合JOIN一起使用。

SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id);

等同于SQL92标准中:

SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id;

二、USING连接与自然连接NATURAL JOIN不同的是,USING指定了具体的相同的字段名称,你需要在USING的括号()中填入要指定的同名字段。同时使用JOIN...USING可以简化JOIN ON的等值连接。
三、表连接的约束条件可以有三种方式:WHEREONUSING

  1. WHERE:适用于所有关联查询
  2. ON:只能和JOIN一起使用,只能写关联条件。虽然关联条件可以并到WHERE中和其他条件一起写,但分开写可读性更好。
  3. USING:只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字段值相等

总结

多表查询分为内连接和外连接

  1. 内连接:取两表交集
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id;  #只有106条记录

SQL99语法:

SELECT table1.column, table2.column,table3.column
FROM table1 
JOIN table2 ON table1 和 table2 的连接条件
JOIN table3 ON table2 和 table3 的连接条件
  1. 外连接:左外连接、右外连接

练习

# 1.显示所有员工的姓名,部门号和部门名称。
# 看到【所有的】想到外连接。MySQL只支持SQL99语法
# 【所有员工】说明查询的数据大多来自【左边】employees表,所以时【左外连接】
SELECT e.last_name,e.department_id,d.department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.`department_id` = d.`department_id`;

# 2.查询90号部门员工的job_id和90号部门的location_id
SELECT e.job_id, d.location_id
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` = 90;


# 3.选择所有有奖金的员工的 last_name , department_name , location_id , city
# 【所有奖金的员工】说明是左外连接,三个表都应该进行左外连接
SELECT e.last_name , d.department_name , d.location_id , l.city
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id
LEFT JOIN locations l
ON d.location_id = l.location_id
WHERE commission_pct IS NOT NULL;

# 4.选择city在Toronto工作的员工的 last_name , job_id , department_id , department_name 
SELECT e.last_name , e.job_id , e.department_id , d.department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id
JOIN locations l
ON d.location_id = l.location_id
WHERE l.`city` = 'Toronto';

# 5.查询员工所在的部门名称、部门地址、姓名、工作、工资,其中员工所在部门的部门名称为’Executive’
SELECT d.department_name,l.street_address,e.last_name,e.job_id,e.salary
FROM employees e JOIN departments d
ON e.department_id = d.department_id
JOIN locations l
ON d.location_id = l.location_id
WHERE d.`department_name` = 'Executive';

# 6.选择指定员工的姓名,员工号,以及他的管理者的姓名和员工号,结果类似于下面的格式
employees	Emp#	manager	Mgr#
kochhar		101	king	100

SELECT emp.last_name "employees",emp.employee_id "Emp#",mgr.last_name "manager", mgr.employee_id "Mgr#"
FROM employees emp LEFT JOIN employees mgr
ON emp.manager_id = mgr.employee_id;

# 7.查询哪些部门没有员工
SELECT d.department_id
FROM departments d LEFT JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;# 只要是e表的字段就行,不用管到底是哪个字段

#本题也可以使用子查询:暂时不讲

# 8. 查询哪个城市没有部门 
SELECT l.country_id
FROM locations l LEFT JOIN departments d
ON l.location_id = d.location_id
WHERE department_id IS NULL;

# 9. 查询部门名为 Sales 或 IT 的员工信息
SELECT last_name 
FROM employees e JOIN departments d
ON e.department_id = d.department_id
WHERE d.department_name = 'Sales' OR d.department_name = 'IT';
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值