文章目录
- 一、笛卡尔积(或交叉连接)的理解
- 二、多表查询分类讲解
- 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 的结果就叫做两个集合的笛卡尔积。并且,从以上结果我们可以看出:
- 两个集合相乘,不满足交换率,即 A×B≠B×A。
- 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): 使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行,组合成新的记录,也就是说,在内连接查询中,只有满足条件的记录才能出现在结果关系中。
连接查询将查询多个表中相关联的行;内连接时,返回查询结果集合中仅是符合查询条件和连接条件的行。有时候需要包含没有关联的行中数据,如下图所示:
如上图所示, 返回查询结果集合中不仅包含符合连接条件的行,还包括 左表
(左外连接或左连接)[右表(右外连接或右连接)或两个边接表(全外连接)]
中的所有数据行。外连接分为左外连接(左连接)和右外连接(右连接):
- LEFT JOIN(左连接):返回包括左表中的所有记录和右表中连接字段相等的记录。左连接的结果包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是连接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果行中,右表的所有选择列表列均为空值。连接条件中左边的表也称为
主表
,右边的表称为从表
。 - 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
- WHERE:适用于所有关联查询;
- ON:只能和 JOIN 一起使用,只能写关联条件。虽然关联条件可以并到 WHERE 中和其他条件一起写,但分开写可读性更好;
- 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 有两个主要的标准,分别是 SQL92
和 SQL99
。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.列出所有没入派的人员和没人入的门派
至此今天的学习就到此结束了,笔者在这里声明,笔者写文章只是为了学习交流,以及让更多学习数据库的读者少走一些弯路,节省时间,并不用做其他用途,如有侵权,联系博主删除即可。感谢您阅读本篇博文,希望本文能成为您编程路上的领航者。祝您阅读愉快!
好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
如果我的博客对你有帮助、如果你喜欢我的博客内容,请点赞
、评论
、收藏
一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
编码不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注
我哦!