七、MySQL 多表查询详解(附练习题及答案----超详细)

文章目录

  • 一、笛卡尔积(或交叉连接)的理解
  • 二、多表查询分类讲解
    • 2.1 分类1:等值连接 vs 非等值连接
    • 2.2 分类2:自连接 vs 非自连接
    • 2.3 分类3:内连接 vs 外连接
    • 2.4 SQL99语法实现多表查询
      • 2.4.1 内连接
      • 2.4.2 左连接
      • 2.4.3 右连接
      • 2.4.4 满外连接(FULL OUTER JOIN)
      • 2.4.5 补充:合并查询结果 UNION 使用
    • 2.5 7种 SQL JOINS 的实现
    • 2.6 SQL99语法新特性
      • 2.6.1 自然连接
      • 2.6.2 USING连接
    • 2.7 小结
    • 2.8 SQL 标准补充
  • 三、课后练习

连接是关系数据库模型的主要特点。连接查询是关系数据库中最主要的查询,主要包括内连接、外连接等。通过连接运算符可以实现多个表查询 (故也称为多表查询)。 在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中。在查询数据时,通过连接操作查询出存放在多个表中的不同实体的信息。当两个或多个表中存在相同意义的字段时,便可以通过这些字段对不同的表进行连接查询。本文将介绍多表之间的内连接查询、外连接查询以及复合条件连接查询。

前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个 关联字段可能建立了外键,也可能没有建立外键。比如:员工表和部门表,这两个表依靠 部门编号 进行关联。
七、MySQL 多表查询详解(附练习题及答案----超详细)_第1张图片

前置知识:

一、数据库开发与实战专栏导学及数据库基础概念入门
二、MySQL 介绍及 MySQL 安装与配置
三、MySQL 数据库的基本操作
四、MySQL 存储引擎及数据类型
五、数据导入与基本的 SELECT 语句
六、MySQL 数据库练习题1(包含前5章练习题目及答案)

一、笛卡尔积(或交叉连接)的理解

笛卡尔积(Cartesian product)是指两个集合 X 和 Y 的乘积。例如,有 A 和 B 两个集合,它们的值如下:

A = {1,2}
B = {3,4,5}

集合 A×B 和 B×A 的结果集分别表示为:

A×B={(1,3), (1,4), (1,5), (2,3), (2,4), (2,5) };
B×A={(3,1), (3,2), (4,1), (4,2), (5,1), (5,2) };

以上 A×B 和 B×A 的结果就叫做两个集合的笛卡尔积。并且,从以上结果我们可以看出:

  1. 两个集合相乘,不满足交换率,即 A×B≠B×A。
  2. A 集合和 B 集合的笛卡尔积是 A 集合的元素个数 × B 集合的元素个数。

图示:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第2张图片

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 加入有效的连接条件。 交叉连接的语法格式如下:

#语法格式1
SELECT <字段名> FROM <1> CROSS JOIN <2> [WHERE子句]
#语法格式2
SELECT <字段名> FROM <1>, <2> [WHERE子句] 
#字段名:需要查询的字段名称。在表中有相同列时,在列名之前加上表名前缀
#<表1><表2>:需要交叉连接的表名
#WHERE 子句:用来设置交叉连接的查询条件

注意: 多个表交叉连接时,在 FROM 后连续使用 CROSS JOIN, 即可。以上两种语法的返回结果是相同的,但是第一种语法才是官方建议的标准写法。当连接的表之间没有关系时,我们会省略掉 WHERE 子句,这时返回结果就是两个表的笛卡尔积,返回结果数量就是两个表的数据行相乘。需要注意的是,如果每个表有 1000 行,那么返回结果的数量就有 1000×1000 = 1000000 行,数据量是非常巨大的,就是上述所说的笛卡尔积错误,得到的运行结果没太大的意义。

【示例1】查询员工姓名和所在部门名称(正确写法)。

SELECT emp.last_name,dep.department_name FROM employees emp,departments dep WHERE emp.department_id=dep.department_id;
SELECT emp.last_name,dep.department_name FROM employees emp CROSS JOIN departments dep ON emp.department_id=dep.department_id;

如果在交叉连接时使用 WHERE 子句,MySQL 会先生成两个表的笛卡尔积,然后再选择满足 WHERE 条件的记录。因此,表的数量较多时,交叉连接会非常非常慢。一般情况下不建议使用交叉连接。在 MySQL 中,多表查询一般使用内连接和外连接,它们的效率要高于交叉连接。

二、多表查询分类讲解

2.1 分类1:等值连接 vs 非等值连接

等值连接:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第3张图片
SQL 语句如下所示:

mysql> SELECT emp.last_name,dep.department_name,dep.location_id
    -> FROM employees emp,departments dep
    -> WHERE emp.department_id=dep.department_id;

【示例2】查询员工姓名和所在部门名称(正确写法)。多个连接条件与 AND 操作符:

#1.区分重复的列名 多个表中有相同列时,必须在列名之前加上表名前缀
#2.使用别名可以简化查询 列名前使用表名前缀可以提高查询效率
SELECT emp.last_name,emp.department_id,dep.department_name,dep.location_id 
FROM employees emp,departments dep 
WHERE emp.department_id=dep.department_id AND dep.department_id=50;
#3.需要注意的是,如果我们使用了表的别名,在查询字段中、过滤条件中就只能使用别名进行代替,使用原表名会报错!

【示例3】连接多个表:查询出公司员工的 last_name、department_name、city。

mysql> SELECT emp.last_name,emp.department_id,dep.department_name,dep.location_id, loc.city
    -> FROM employees emp,departments dep,locations loc
    -> WHERE emp.department_id=dep.department_id AND dep.location_id=loc.location_id;

非等值连接:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第4张图片
【示例4】非等值连接。使用sql语句实现上图所示查询结果。

mysql> SELECT emp.last_name,emp.salary,gra.grade_level,gra.lowest_sal,gra.highest_sal
    -> FROM employees emp,job_grades gra
    -> WHERE emp.salary BETWEEN gra.lowest_sal AND gra.highest_sal;

2.2 分类2:自连接 vs 非自连接

【示例5】查询出员工的 manager 的信息。

mysql> SELECT
    -> emp1.employee_id,emp1.last_name,emp1.manager_id,
    -> emp2.employee_id,emp2.last_name
    -> FROM employees emp1, employees emp2
    -> WHERE emp1.manager_id=emp2.employee_id;

查询结果如下图所示:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第5张图片
emp1 和 emp2 本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询。【示例6】查询出 last_name为 Chen 的员工的 manager 的信息。

mysql> SELECT
    -> emp1.employee_id,emp1.last_name,emp1.manager_id,
    -> emp2.employee_id,emp2.last_name
    -> FROM employees emp1, employees emp2
    -> WHERE emp1.manager_id=emp2.employee_id AND emp1.last_name='Chen';
+-------------+-----------+------------+-------------+-----------+
| employee_id | last_name | manager_id | employee_id | last_name |
+-------------+-----------+------------+-------------+-----------+
|         110 | Chen      |        108 |         108 | Greenberg |
+-------------+-----------+------------+-------------+-----------+
1 row in set (0.00 sec)

2.3 分类3:内连接 vs 外连接

内连接(INNER JOIN): 使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行,组合成新的记录,也就是说,在内连接查询中,只有满足条件的记录才能出现在结果关系中。

连接查询将查询多个表中相关联的行;内连接时,返回查询结果集合中仅是符合查询条件和连接条件的行。有时候需要包含没有关联的行中数据,如下图所示:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第6张图片
如上图所示, 返回查询结果集合中不仅包含符合连接条件的行,还包括 左表(左外连接或左连接)[右表(右外连接或右连接)或两个边接表(全外连接)] 中的所有数据行。外连接分为左外连接(左连接)和右外连接(右连接):

  1. LEFT JOIN(左连接):返回包括左表中的所有记录和右表中连接字段相等的记录。左连接的结果包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果行中,右表的所有选择列表列均为空值。连接条件中左边的表也称为 主表 ,右边的表称为 从表
  2. RIGHT JOIN(右连接):返回包括右表中的所有记录和左表中连接字段相等的记录。右连接是左连接的反向连接,将返回右表的所有行。如果右表的某行在左表中没有匹配行,左表将返回空值。如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表

2.4 SQL99语法实现多表查询

2.4.1 内连接

内连接的语法格式如下:

SELECT <字段名> FROM <1> INNER JOIN <2> [ON子句]
#字段名:需要查询的字段名称。
#<表1><表2>:需要内连接的表名。
#INNER JOIN :内连接中可以省略 INNER 关键字,只用关键字 JOIN。
#ON 子句:用来设置内连接的连接条件。

多个表内连接时,在 FROM 后连续使用 INNER JOIN 或 JOIN 即可。

INNER JOIN 也可以使用 WHERE 子句指定连接条件,但是 INNER JOIN … ON 语法是官方的标准写法,而且 WHERE 子句在某些时候会影响查询的性能。

【示例7】查询员工信息及其部门信息。

mysql> SELECT
    -> emp1.employee_id,emp1.last_name,emp1.department_id,
    -> dep.department_id,dep.location_id
    -> FROM employees emp1 INNER JOIN departments dep
    -> ON emp1.department_id=dep.department_id;

【示例8】查询出员工的 manager 的信息。

mysql> SELECT
    -> emp1.employee_id,emp1.last_name,emp1.manager_id,
    -> emp2.employee_id,emp2.last_name
    -> FROM employees emp1 INNER JOIN employees emp2
    -> ON emp1.manager_id=emp2.employee_id;

【示例9】多表连接三张表。

mysql> SELECT
    -> emp1.employee_id,emp1.last_name,emp1.department_id,
    -> dep.department_id,dep.location_id,loc.city,loc.state_province
    -> FROM employees emp1 INNER JOIN departments dep
    -> ON emp1.department_id=dep.department_id
    -> INNER JOIN locations loc ON dep.location_id = loc.location_id;

2.4.2 左连接

左外连接又称为左连接,使用 LEFT OUTER JOIN 关键字连接两个表,并使用 ON 子句来设置连接条件。左连接的语法格式如下:

SELECT <字段名> FROM <1> LEFT OUTER JOIN <2> <ON子句>
#字段名:需要查询的字段名称。
#<表1><表2>:需要左连接的表名。
#LEFT OUTER JOIN:左连接中可以省略 OUTER 关键字,只使用关键字 LEFT JOIN。
#ON 子句:用来设置左连接的连接条件,不能省略。

上述语法中,表1 为主表,表2 为从表。左连接查询时,可以查询出 表1 中的所有记录和 表2 中匹配连接条件的记录。如果 表1 的某行在 表2 中没有匹配行,那么在返回结果中,表2 的字段值均为 空值(NULL), 在之前已经提过。

mysql> SELECT
    ->   dep.department_id,dep.location_id,
    -> emp.employee_id,emp.last_name,emp.department_id
    -> FROM departments dep LEFT OUTER JOIN employees emp
    -> ON dep.department_id=emp.department_id;

2.4.3 右连接

右外连接又称为右连接,右连接是左连接的反向连接。使用 RIGHT OUTER JOIN 关键字连接两个表,并使用 ON 子句来设置连接条件。右连接的语法格式如下:

SELECT <字段名> FROM <1> RIGHT OUTER JOIN <2> <ON子句>
#字段名:需要查询的字段名称。
#<表1><表2>:需要右连接的表名。
#RIGHT OUTER JOIN:右连接中可以省略 OUTER 关键字,只使用关键字 RIGHT JOIN。
#ON 子句:用来设置右连接的连接条件,不能省略。

与左连接相反,右连接以 表2 为主表,表1 为从表。右连接查询时,可以查询出 表2 中的所有记录和 表1 中匹配连接条件的记录。如果 表2 的某行在 表1 中没有匹配行,那么在返回结果中,表1 的字段值均为空值(NULL)。

mysql> SELECT
    ->   dep.department_id,dep.location_id,
    -> emp.employee_id,emp.last_name,emp.department_id
    -> FROM departments dep RIGHT OUTER JOIN employees emp
    -> ON dep.department_id=emp.department_id;

多个表左/右连接时,在 ON 子句后连续使用 LEFT/RIGHT OUTER JOIN 或 LEFT/RIGHT JOIN 即可。使用外连接查询时,一定要分清需要查询的结果,是需要显示左表的全部记录还是右表的全部记录,然后选择相应的左连接和右连接。

2.4.4 满外连接(FULL OUTER JOIN)

满外连接的结果 = 左右表匹配的数据 + 左表没有匹配到的数据 + 右表没有匹配到的数据。
SQL99是支持满外连接的。使用 FULL JOIN 或 FULL OUTER JOIN 来实现。需要注意的是,MySQL 不支持 FULL JOIN,但是可以用 LEFT JOIN UNION RIGHT JOIN 代替。

2.4.5 补充:合并查询结果 UNION 使用

利用 UNION 关键字,可以给出多条 SELECT 语句,并将它们的结果组合成单个结果集。合并时,两个表对应的列数和数据类型必须相同。各个 SELECT 语句之间使用 UNION 或 UNION ALL 关键字分隔。UNION 不使用关键字 ALL,执行的时候删除重复的记录,所有返回的行都是唯一的;使用关键字 ALL 的作用是不删除重复行也不对结果进行自动排序。基本语法格式如下:

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

注意: 执行 UNION ALL 语句时所需要的资源比 UNION 语句少。如果明确知道合并数据后的结果数据不存在重复数据,或者不需要去除重复的数据,则尽量使用 UNION ALL 语句,以提高数据查询的效率。【示例10】查询部门编号>90或邮箱包含a的员工信息。

mysql> SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;
mysql> SELECT * FROM employees WHERE email LIKE '%a%' UNION
    -> SELECT * FROM employees WHERE department_id>90;
mysql> SELECT * FROM employees WHERE email LIKE '%a%' UNION ALL#有重复数据
    -> SELECT * FROM employees WHERE department_id>90;

2.5 7种 SQL JOINS 的实现

七、MySQL 多表查询详解(附练习题及答案----超详细)_第7张图片
sql 示例:

mysql> SELECT employee_id,last_name,department_name FROM employees e LEFT JOIN departments d
    -> ON e.`department_id` = d.`department_id`;

右连接:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第8张图片
sql 示例:

mysql> SELECT employee_id,last_name,department_name FROM employees e RIGHT JOIN departments d
    -> ON e.`department_id` = d.`department_id`;

内连接:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第9张图片
sql 示例:

mysql> SELECT employee_id,last_name,department_name FROM employees e INNER JOIN departments d
    -> ON e.`department_id` = d.`department_id`;

全连接:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第10张图片
sql 示例:

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

剩下的三个图:
七、MySQL 多表查询详解(附练习题及答案----超详细)_第11张图片
sql 示例:

mysql> #左图
mysql> SELECT employee_id,last_name,department_name
    -> FROM employees e LEFT JOIN departments d
    -> ON e.`department_id` = d.`department_id`
    -> WHERE d.`department_id` IS NULL
    -> ;
+-------------+-----------+-----------------+
| employee_id | last_name | department_name |
+-------------+-----------+-----------------+
|         178 | Grant     | NULL            |
+-------------+-----------+-----------------+
1 row in set (0.00 sec)

mysql> #右图
mysql> SELECT employee_id,last_name,department_name
    -> FROM employees e RIGHT JOIN departments d
    -> ON e.`department_id` = d.`department_id`
    -> WHERE e.`department_id` IS NULL;
+-------------+-----------+----------------------+
| employee_id | last_name | department_name      |
+-------------+-----------+----------------------+
|        NULL | NULL      | Treasury             |
|        NULL | NULL      | Corporate Tax        |
|        NULL | NULL      | Control And Credit   |
|        NULL | NULL      | Shareholder Services |
|        NULL | NULL      | Benefits             |
|        NULL | NULL      | Manufacturing        |
|        NULL | NULL      | Construction         |
|        NULL | NULL      | Contracting          |
|        NULL | NULL      | Operations           |
|        NULL | NULL      | IT Support           |
|        NULL | NULL      | NOC                  |
|        NULL | NULL      | IT Helpdesk          |
|        NULL | NULL      | Government Sales     |
|        NULL | NULL      | Retail Sales         |
|        NULL | NULL      | Recruiting           |
|        NULL | NULL      | Payroll              |
+-------------+-----------+----------------------+
16 rows in set (0.00 sec)

mysql> #中图
mysql> SELECT employee_id,last_name,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,last_name,department_name
    -> FROM employees e RIGHT JOIN departments d
    -> ON e.`department_id` = d.`department_id`
    -> WHERE e.`department_id` IS NULL;
+-------------+-----------+----------------------+
| employee_id | last_name | department_name      |
+-------------+-----------+----------------------+
|         178 | Grant     | NULL                 |
|        NULL | NULL      | Treasury             |
|        NULL | NULL      | Corporate Tax        |
|        NULL | NULL      | Control And Credit   |
|        NULL | NULL      | Shareholder Services |
|        NULL | NULL      | Benefits             |
|        NULL | NULL      | Manufacturing        |
|        NULL | NULL      | Construction         |
|        NULL | NULL      | Contracting          |
|        NULL | NULL      | Operations           |
|        NULL | NULL      | IT Support           |
|        NULL | NULL      | NOC                  |
|        NULL | NULL      | IT Helpdesk          |
|        NULL | NULL      | Government Sales     |
|        NULL | NULL      | Retail Sales         |
|        NULL | NULL      | Recruiting           |
|        NULL | NULL      | Payroll              |
+-------------+-----------+----------------------+
17 rows in set (0.00 sec)

2.6 SQL99语法新特性

2.6.1 自然连接

SQL99 在 SQL92 的基础上提供了一些特殊语法,比如 NATURAL JOIN 用来表示自然连接。我们可以把自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中 所有相同的字段,然后进行 等值连接。在 SQL92 标准中:

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

在 SQL99 中你可以写成:

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

2.6.2 USING连接

当我们进行连接的时候,SQL99 还支持使用 USING 指定数据表里的 同名字段 进行等值连接。但是只能配合 JOIN 一起使用。比如:

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

你能看出与自然连接 NATURAL JOIN 不同的是,USING 指定了具体的相同的字段名称,你需要在 USING 的括号 () 中填入要指定的同名字段。同时使用 JOIN...USING 可以简化 JOIN ON 的等值连接。它与下面的 SQL 查询结果是相同的:

mysql> SELECT employee_id,last_name,department_name FROM employees e ,departments d
    -> WHERE e.department_id = d.department_id;

2.7 小结

表连接的约束条件可以有三种方式:WHERE、ON、USING

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

sql 示例:

#关联条件
#把关联条件写在where后面
SELECT last_name,department_name FROM employees,departments
WHERE employees.department_id = departments.department_id;

#把关联条件写在on后面,只能和JOIN一起使用
SELECT last_name,department_name FROM employees INNER JOIN departments
ON employees.department_id = departments.department_id;

SELECT last_name,department_name FROM employees CROSS JOIN departments
ON employees.department_id = departments.department_id;

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

#把关联字段写在using()中,只能和JOIN一起使用
#而且两个表中的关联字段必须名称相同,而且只能表示=
#查询员工姓名与基本工资 
SELECT last_name,job_title
FROM employees INNER JOIN jobs USING(job_id);

#n张表关联,需要n-1个关联条件
#查询员工姓名,基本工资,部门名称
SELECT last_name,job_title,department_name FROM employees,departments,jobs 
WHERE employees.department_id = departments.department_id
AND employees.job_id = jobs.job_id;

SELECT last_name,job_title,department_name
FROM employees INNER JOIN departments INNER JOIN jobs 
ON employees.department_id = departments.department_id AND employees.job_id = jobs.job_id;

注意: 我们要 控制连接表的数量。多表连接就相当于嵌套 for 循环一样,非常消耗资源,会让 SQL 查询性能下降得很严重,因此不要连接不必要的表。在许多 DBMS 中,也都会有最大连接表的限制。

强制: 超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询时, 保证被关联的字段需要有索引。说明: 即使双表 join 也要注意表索引、SQL 性能。

2.8 SQL 标准补充

SQL 存在不同版本的标准规范,因为不同规范下的表连接操作是有区别的。SQL 有两个主要的标准,分别是 SQL92SQL99。92 和 99 代表了标准提出的时间,SQL92 就是 92 年提出的标准规范。当然除了 SQL92 和 SQL99 以外,还存在 SQL-86、SQL-89、SQL:2003、SQL:2008、SQL:2011 和 SQL:2016 等其他的标准。这么多标准,到底该学习哪个呢?实际上最重要的 SQL 标准就是 SQL92 和 SQL99。 一般来说 SQL92 的形式更简单,但是写的 SQL 语句会比较长,可读性较差。而 SQL99 相比于 SQL92 来说,语法更加复杂, 但可读性更强。我们从这两个标准发布的页数也能看出,SQL92 的标准有 500 页,而 SQL99 标准超过了 1000 页。实际上从 SQL99 之后,很少有人能掌握所有内容,因为确实太多了。就好比我们使用 Windows、Linux 和 Office 的时候,很少有人能掌握全部内容一样。我们只需要掌握一些核心的功能,满足日常工作的需求即可。

SQL92 和 SQL99 是经典的 SQL 标准,也分别叫做 SQL-2 和 SQL-3 标准。 也正是在这两个标准发布之后,SQL 影响力越来越大,甚至超越了数据库领域。现如今 SQL 已经不仅仅是数据库领域的主流语言, 还是信息领域中信息处理的主流语言。在图形检索、图像检索以及语音检索中都能看到 SQL 语言的使用。

三、课后练习

1、显示所有员工的姓名,部门号和部门名称。

SELECT emp.last_name,emp.department_id,dep.department_name
FROM employees emp LEFT OUTER JOIN departments dep
ON emp.department_id = dep.department_id;

2、查询90号部门员工的job_id和90号部门的location_id。

SELECT emp.job_id,dep.location_id
FROM employees emp LEFT OUTER JOIN departments dep
ON emp.department_id = dep.department_id
WHERE emp.department_id = 90;
#或
SELECT emp.job_id,dep.location_id
FROM employees emp JOIN departments dep
ON emp.department_id = dep.department_id
WHERE emp.department_id = 90;
#或
SELECT job_id, location_id
FROM employees e, departments d
WHERE e.`department_id` = d.`department_id`
AND e.`department_id` = 90;

3、选择所有有奖金的员工的 last_name、department_name、location_id、city。

mysql> SELECT last_name , department_name , d.location_id , city
    -> FROM employees e
    -> LEFT OUTER JOIN departments d
    -> ON e.`department_id` = d.`department_id`
    -> LEFT OUTER 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。

mysql> SELECT last_name , job_id , e.department_id , department_name
    -> FROM employees e, departments d, locations l
    -> WHERE e.`department_id` = d.`department_id`
    -> AND d.`location_id` = l.`location_id`
    -> AND city = 'Toronto';
+-----------+--------+---------------+-----------------+
| last_name | job_id | department_id | department_name |
+-----------+--------+---------------+-----------------+
| Hartstein | MK_MAN |            20 | Marketing       |
| Fay       | MK_REP |            20 | Marketing       |
+-----------+--------+---------------+-----------------+
2 rows in set (0.00 sec)

mysql> SELECT emp.last_name,emp.job_id,dep.department_id,dep.department_name
    -> FROM employees emp INNER JOIN departments dep
    -> ON emp.department_id = dep.department_id
    -> INNER JOIN locations loc ON dep.location_id = loc.location_id
    -> WHERE loc.city='Toronto';
+-----------+--------+---------------+-----------------+
| last_name | job_id | department_id | department_name |
+-----------+--------+---------------+-----------------+
| Hartstein | MK_MAN |            20 | Marketing       |
| Fay       | MK_REP |            20 | Marketing       |
+-----------+--------+---------------+-----------------+
2 rows in set (0.00 sec)

5、查询哪些部门没有员工。

mysql> SELECT dep.department_id,dep.department_name FROM departments dep
    -> LEFT JOIN employees emp ON dep.department_id = emp.department_id
    -> WHERE emp.department_id IS NULL;
+---------------+----------------------+
| department_id | department_name      |
+---------------+----------------------+
|           120 | Treasury             |
|           130 | Corporate Tax        |
|           140 | Control And Credit   |
|           150 | Shareholder Services |
|           160 | Benefits             |
|           170 | Manufacturing        |
|           180 | Construction         |
|           190 | Contracting          |
|           200 | Operations           |
|           210 | IT Support           |
|           220 | NOC                  |
|           230 | IT Helpdesk          |
|           240 | Government Sales     |
|           250 | Retail Sales         |
|           260 | Recruiting           |
|           270 | Payroll              |
+---------------+----------------------+
16 rows in set (0.00 sec)

剩下的几个自己练习:

#1.查询员工所在的部门名称、部门地址、姓名、工作、工资,其中员工所在部门的部门名称为 'Executive'
#2.选择指定员工的姓名,员工号,以及他的管理者的姓名和员工号,结果类似于下面的格式
#employees Emp# manager Mgr#
#kochhar 101 king 100
#3.查询哪个城市没有部门
#4.查询部门名为 Sales 或 IT 的员工信息
#创建表及数据准备
CREATE TABLE `t_dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `t_emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
empno int not null,
PRIMARY KEY (`id`),
KEY `idx_dept_id` (`deptId`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO t_dept(deptName,address) VALUES('华山','华山');
INSERT INTO t_dept(deptName,address) VALUES('丐帮','洛阳');
INSERT INTO t_dept(deptName,address) VALUES('峨眉','峨眉山');
INSERT INTO t_dept(deptName,address) VALUES('武当','武当山');
INSERT INTO t_dept(deptName,address) VALUES('明教','光明顶');
INSERT INTO t_dept(deptName,address) VALUES('少林','少林寺');
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('风清扬',90,1,100001);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('岳不群',50,1,100002);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('令狐冲',24,1,100003);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('洪七公',70,2,100004);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('乔峰',35,2,100005);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('灭绝师太',70,3,100006);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('周芷若',20,3,100007);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('张三丰',100,4,100008);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('张无忌',25,5,100009);
INSERT INTO t_emp(NAME,age,deptId,empno) VALUES('韦小宝',18,null,100010);

#练习: 7种JOIN
#1.所有有门派的人员信息
#2.列出所有用户,并显示其机构信息
#3.列出所有门派
#4.所有不入门派的人员
#5.所有没人入的门派
#6.列出所有人员和机构的对照关系
#MySQL Full Join的实现 因为MySQL不支持FULL JOIN,下面是替代方法
#left join + union(可去除重复数据)+ right join
#7.列出所有没入派的人员和没人入的门派

至此今天的学习就到此结束了,笔者在这里声明,笔者写文章只是为了学习交流,以及让更多学习数据库的读者少走一些弯路,节省时间,并不用做其他用途,如有侵权,联系博主删除即可。感谢您阅读本篇博文,希望本文能成为您编程路上的领航者。祝您阅读愉快!


在这里插入图片描述

    好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
    如果我的博客对你有帮助、如果你喜欢我的博客内容,请 点赞评论收藏 一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
 编码不易,大家的支持就是我坚持下去的动力。点赞后不要忘了 关注 我哦!

你可能感兴趣的:(MySQL8.0从菜鸟到大牛,mysql,数据库,sql)