目录
一、为什么需要多表查询?
查询一个员工名为“Abel”的人在哪个城市工作?
二、如何实现多表查询
1.出现笛卡尔积(交叉连接)的错误
①错误的实现方式
②错误的原因
2.多表查询的正确方式 —— 需要有连接条件
①两个表的连接条件
② 如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表
3.可以给表起别名,在SELECT和WHERE中使用表的别名
注意
三、多表查询的分类
1.等值连接&非等值连接
⚪非等值连接
2.自连接&非自连接
#查询员工id,员工姓名及其管理者的id和姓名 —— 自连接
3.内连接&外连接
①内连接
②外连接
⚪SQL92语法实现外连接 :使用 +
⚪SQL99语法实现多表的查询
Ⅰ.SQL99语法实现内连接
Ⅱ.SQL99语法实现外连接
左外连接:
右外连接:
满外连接:
Ⅲ.使用SQL99实现7种JOIN操作
·图③的实现 :内连接
·图①的实现 :左外连接
·图②的实现 :右外连接
·图④的实现
·图⑤的实现
·图⑥的实现:满外连接
·图⑦的实现
Ⅳ.补充:UNION和UNION ALL的使用
1.合并查询结果
2.UNION 操作符
3..UNION ALL操作符
四、SQL99语法的新特性
1.自然连接
2.USING连接
⚪表连接的约束条件可以有三种方式:WHERE, ON, USING
五、相关的表
1.employees表
2.departments表
3.locations表
1.先查询出他的全部信息
SELECT *
FROM employees
WHERE last_name = 'Abel';
2.得知他在80号部门时,查询80号部门的信息
SELECT *
FROM departments
WHERE department_id = 80;
SELECT *
FROM locations
WHERE location_id = 2500;
笛卡尔乘积是一个数学运算。
假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能 组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。
组合的个数即为两个集合中元素个数的乘积数
每个员工都与每个部门匹配了一遍
SELECT employee_id,department_name
FROM employees,departments; #查询出2889条记录
SELECT employee_id,department_name
FROM employees CROSS JOIN departments;
为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。
SELECT employee_id,department_name
FROM employees,departments
WHERE employees.department_id = departments.department_id; #106条 (不包含NULL)
SELECT employee_id,department_name,department_id
FROM employees,departments
WHERE employees.department_id = departments.department_id; #106条 (不包含NULL)
department_id在employees和departments表中都存在,未指明在哪个表中时:
SELECT employee_id,department_name,employees.department_id
FROM employees,departments
WHERE employees.department_id = departments.department_id; #106条 (不包含NULL)
从sql优化的角度,建议多表查询时,每个字段前都指明其所在的表
SELECT employees.employee_id,departments.department_name,department_id FROM employees,departments WHERE employees.department_id = departments.department_id; #106条 (不包含NULL)
SELECT emp.employee_id,dept.department_name,dept.department_id
FROM employees emp,departments dept
WHERE emp.department_id = dept.department_id; #106条 (不包含NULL)
如果给表起了别名,一旦在SELECT或WHERE中使用表的别名的话,则必须使用表的别名,而不能再使用表的原名
非等值连接的例子
SELECT *
FROM job_grades;
SELECT last_name,salary,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;
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,departments
WHERE employees.department_id = departments.department_id; #106条 (不包含NULL)
两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的 行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。
外连接的分类:左外连接,右外连接,满外连接
如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 。
如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表 。
查询所有的员工的 employee_id,department_name信息
MySQL不支持SQL92语法中外连接的写法
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.department_id = d.department_id(+);
使用JOIN ... ON 的方式实现多表的查询。这种方式也能解决外连接的问题,且MySQL支持
SELECT employee_id,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 employee_id,department_name,city
FROM employees e LEFT JOIN departments d
ON e.department_id = d.department_id;
SELECT employee_id,department_name,city
FROM employees e RIGHT JOIN departments d
ON e.department_id = d.department_id;
MySQL不支持FULL OUTER JOIN
SELECT employee_id,department_name,city
FROM employees e FULL OUTER JOIN departments d
ON e.department_id = d.department_id;
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;
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;
利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNION或UNION ALL关键字分隔。
UNION 操作符返回两个查询的结果集的并集,去除重复记录。
UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。
注意:执行UNION ALL语句时所需要的资源比UNION语句少。如果明确知道合并数据后的结果数据 不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效率。
SQL99 在 SQL92 的基础上提供了一些特殊语法,比如 NATURAL JOIN 用来表示自然连接。我们可以把 自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中 所有相同的字段 ,然后进行等值 连接 。
在 SQL99 中你可以写成:
SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;
当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的 同名字段进行等值连接。但是只能配合JOIN一起使用。比如:
你能看出与自然连接 NATURAL JOIN 不同的是,USING 指定了具体的相同的字段名称,你需要在 USING 的括号 () 中填入要指定的同名字段。同时使用 JOIN...USING 可以简化 JOIN ON 的等值连接。它与下 面的 SQL 查询结果是相同的:
SELECT employee_id,last_name,department_name
FROM employees e ,departments d
WHERE e.department_id = d.department_id;
WHERE:适用于所有关联查询
ON :只能和JOIN一起使用,只能写关联条件。虽然关联条件可以并到WHERE中和其他条件一起 写,但分开写可读性更好。
USING:只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字 段值相等