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

news2024/11/19 6:23:11

文章目录

  • 一、笛卡尔积(或交叉连接)的理解
  • 二、多表查询分类讲解
    • 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 介绍及 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 集合的元素个数。

图示:

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 非等值连接

等值连接:
在这里插入图片描述
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;

非等值连接:
在这里插入图片描述
【示例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;

查询结果如下图所示:
在这里插入图片描述
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): 使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行,组合成新的记录,也就是说,在内连接查询中,只有满足条件的记录才能出现在结果关系中。

连接查询将查询多个表中相关联的行;内连接时,返回查询结果集合中仅是符合查询条件和连接条件的行。有时候需要包含没有关联的行中数据,如下图所示:
在这里插入图片描述
如上图所示, 返回查询结果集合中不仅包含符合连接条件的行,还包括 左表(左外连接或左连接)[右表(右外连接或右连接)或两个边接表(全外连接)] 中的所有数据行。外连接分为左外连接(左连接)和右外连接(右连接):

  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 的实现

在这里插入图片描述
sql 示例:

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

右连接:
在这里插入图片描述
sql 示例:

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

内连接:
在这里插入图片描述
sql 示例:

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

全连接:
在这里插入图片描述
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`;

剩下的三个图:
在这里插入图片描述
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.列出所有没入派的人员和没人入的门派

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


在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/157214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

System Description 步骤

纲要&#xff1a; 在有了Composition以后&#xff0c;下一步就是把它分配到ECU里面。 1. Create System Description Import DBC file, select ECUs and CAN Frames under the DBC. Then it will create "SystemDescription.arxml" file. [1] 2. Check the content…

地图下载器代码结构设计及功能实现

jcef包引入表结构设计后台关键代码结构前端关键代码结构功能展示启动页底图切换绘制选择下载区域行政区划切换选择下载区域下载关键代码import { InnerMqClient } from ../../rx/inner-mq.service;import { SubmitService } from ../../service/submit.service;import { MapBas…

马蹄集 字符判断

字符判断 难度&#xff1a;白银 时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 输入一个字符&#xff0c;判断是数字字符、大写字母、小写字母、算术运算符、 关系运算符、逻辑运算符&#xff0c;还是其他字符&#xff0c;分别输出Number?”, "Capital letter?”,…

Springboot集成knife4j文档时,接口信息没有显示

我使用的 SpringBoot、knife4j 版本jar包如下所示&#xff1a;<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version><relativePath/> …

kube-bench初体验

kube-bench是一个通过运行CIS Kubernetes benchmark中记录的checker来检查Kubernetes是否安全部署的工具。测试&#xff0c;找gap&#xff0c;audit&#xff0c;都可以啊关于CIS k8s benchmark 参见 CIS Kubernetes Benchmarks (cisecurity.org)就是说&#xff0c;想做k8s加固&…

再学C语言32:函数——多源代码文件程序及其编译

使用多个函数时&#xff0c;最简单的方法是将所有函数放在同一文件中&#xff0c;就像编译单个函数的文件一样对该文件进行编译 具体的编译过程根据操作系统不同而具有差异性 Window系统下的编译器是面向工程的 工程&#xff08;project&#xff09;&#xff1a;描述了一个特…

【Linux】项目自动化构建工具—make/makefile

文章目录1. 什么是make/makefile&#xff1f;2. make/makefile的使用2.1 实例代码2.2 依赖关系和依赖方法2.3 项目清理2.4 make是如何确定是否编译的3. Linux第一个小程序—进度条3.1 \r 和 \n3.2 进度条小程序1. 什么是make/makefile&#xff1f; make是一个命令工具&#xf…

【Spring6源码・IOC】Bean的初始化 - 终结篇

前面两篇&#xff0c;我们着重讲解了一下《BeanDefinition的加载》和《bean的实例化》。 这一篇我们来讲解一下bean的初始化。 我们这里的案例依旧是以SpringBoot3.0、JDK17为前提&#xff0c;案例代码如下&#xff1a; Component public class A {Autowiredprivate B b;}Com…

Windows+iis+php+mysql搭建wordpress

准备工作 WindowsServer一台 IIS&#xff0c;在Server上开启 PHP:PHP: Downloads Mysql:MySQL :: MySQL Downloads wordpress下载 | WordPress.org China 简体中文 PHP程序在IIS上以fastcgi方式运行&#xff0c;在安装mysql和php之前确保vc库已安装。 IIS确保开启CGI模块…

JAVA开发(AOP之ProceedingJoinPoint)

我们在开发过程中经常使用到自定义注解来实现在一些类或者方法执行过程中切面&#xff0c;统一实现某些业务操作。例如自定义注解import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang…

YOLOv7:面向实时检测的目标检测器 | 附结构图

YOLOv7 在 5 FPS 到 160 FPS 范围内的速度和准确度都超过了所有已知的目标检测器&#xff0c;并且在 GPU V100 上 30 FPS 或更高的所有已知实时目标检测器中具有最高的准确度 56.8% AP。 YOLOv7-E6 目标检测器&#xff08;56 FPS V100&#xff0c;55.9% AP&#xff09;比基于Tr…

小孩护眼灯什么牌子的好?分享四款最好的台灯品牌

最近发现&#xff0c;在接送我家神兽上下学时&#xff0c;小朋友们会揉眼睛&#xff0c;眼睛始终没睁开的感觉&#xff0c;还有不少小学就戴上了眼镜&#xff0c;我深知戴眼镜&#xff0c;真的很麻烦&#xff0c;所以更加看重孩子的护眼工作。市面上越来越多护眼灯&#xff0c;…

Java高手速成 | 实现人物拼图游戏

拼图游戏指将一幅图片分割成若干拼块&#xff0c;并随机打乱顺序&#xff0c;当将所有拼块都放回原位置时就完成了拼图(游戏结束)。 01、游戏介绍 在游戏中&#xff0c;拼块以随机顺序排列&#xff0c;网格上有一个位置是空的。完成拼图的方法是利用这个空位置移动拼块&#xf…

服务搭建常见问题

怎么将myeclipse项目部署到tomcat服务器 https://www.laike.net/article-162-238315-0.html eclipse提示错误&#xff1a;save could not be completed Dynamic Web Module 4.0 requires Java 1.8 or newer. https://blog.csdn.net/xixihaha_coder/article/details/118345378 …

微星 MPG B460I GAMING EDGE WIFI +i5-10400电脑 Hackintosh 黑苹果efi引导文件

硬件型号驱动情况主板微星 MPG B460I GAMING EDGE WIFI (MS-7C86)&#xff08;LPC Controller B460芯片组&#xff09;处理器英特尔 Core i5-10400 2.90GHz 六核已驱动内存16 GB ( 芝奇 DDR4 2666MHz 8GB x 2 )已驱动硬盘朗科科技 NVMe SSD 480GB (480 GB / 固态硬盘)已驱动显…

React学习笔记:实用又好用的Hooks函数

React框架以前是采用Class类编程&#xff0c;在类编程中使用生命周期比较方便&#xff0c;但是随着迭代更新&#xff0c;官方开始推荐使用函数式编程&#xff0c;但是函数式编程就没有状态这一个概念&#xff0c;于是乎官方就定义了一系列钩子函数来弥补在这一缺陷&#xff0c;…

Rabbitmq(七) -- rabbitmq的工作模式

1. 简单模式&#xff1a;无需交换机 消息产生消息&#xff0c;将消息放入队列消息的消费者(consumer) 监听 消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除(隐患 消息可能没有被消费者正确处理,已经从队列中消失了,造成消息的丢失&#xff0c;这里可以设置…

VTK-数据集vtkUnstructuredGrid

前言&#xff1a;本博文主要介绍vtkUnstructuredGrid的特点、结构组成&#xff0c;vtkUnstructuredGrid的创建方法&#xff0c;及其vtkUnstructuredGrid相关的接口及示例。 特点 非结构化网格数据&#xff0c;是最常见的数据集类型&#xff0c;它的拓扑结构和几何结构都是非结…

Pycharm调试功能介绍

文章目录pycharm中的debug模式debug的断点调试pycharm中的debug模式 在pycharm中&#xff0c;一共有4中方法开启debug调试&#xff0c;如下&#xff1a; 点击导航栏的run >> debug 双击打开py文件 >> 右上角点击小虫子图标。 写好if name ‘main’: >> 点…

React 类组件你不知道的细节+案例

React基础-组件-类组件 1.组件概述 目标&#xff1a;了解React组件的作用和创建组件的方式 什么是组件组件的设计思想 1.what is 组件啊&#xff1f; 在前端开发中组件就是用户界面当中一块独立的区域,在组件内部会包含这块区域中的视图代码,样式代码以及逻辑代码 React是采用…