(一)里面我们以单表查询为基础,讲了DQL语句的基础,这篇我们来讲多表查询。
联合查询
联合查询的作用是合并结果集,也就是把两个select语句的查询结果合并到一起。合并结果集的方式有两种,分别是去重和不去重。语法格式为:
SELECT 字段列表 FROM 表1
UNION [ALL]
SELECT 字段列表 FROM 表2;
# 如果不填ALL,则结果会去重合并,填写ALL之后合并时不再会去重
注意:合并结果集时,需要两个SELECT语句的查询结果列数、数据类型一致,然后会按照列的顺序合并结果集,如果不一致,在执行语句时就会报错。
连接查询
连接查询的结果是各个表之间的笛卡尔积。通俗地讲,就是表1查询结果*表2查询结果*...
这里放一个示例,如下是两张表
# 这是连接查询语句
SELECT * FROM 表1,表2,...;
结果为:
当然,这只是最初的查询结果。在FROM之后依旧可以像单表查询一样添加WHERE等一系列语句来对这个最初的结果集进行筛选(包括SELECT中指定字段列表)。如果两种表有同名的列,想要用它们作为WHERE条件的话,需要使用 表1名.字段名=表2名.字段名 的格式进行标识。
还可以给表使用别名,在表名较长时,可以简化重复的流程。
SELECT e.字段1,e.字段2,e.字段3,d.字段4 FROM 表1 AS e,表2 AS d
WHERE e.同名字段=d.同名字段;
# 同时注意,这里查询的是e表的3个字段和d表的1个字段,不是两张表的4个同名字段。
# 这就是通过SELECET来筛选结果
内连接
其实刚刚上面的语句就是内连接,但它不是标准的查询方式,可以当做MySQL的方言。
标准内连接语句为:
SELECT 字段列表 FROM 表1 INNER JOIN 表2 [ON 连接条件];
内连接查询的结果必须满足连接条件(也可以不设条件,这时候结果就是笛卡尔积),例如有内连接查询条件为 s.id = t.stu_id ,这里又正好有一条s.id 的值为null,那么它就怎么都不会符合连接条件。
又因为null值的特殊性,在查询时你希望将其替换掉,可以使用 IFNULL(字段名,替换值) 。
外连接
与内连接相比,外连接允许查询出的结果不满足条件
# 左外连接
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;
# 右外连接
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;
左外连接
# 左外连接
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;
左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。
仔细讲,假设连接条件为左表.id = 右表.stu_id,在左表的一条记录中,id字段为6666,而右表中不存在stu_id为6666的记录(NULL值有特殊性),所以左表这条记录,不能满足连接条件。但在左连接中,左表中的记录都会查询出来,即这条id字段值为6666的记录也会查出,但相应的右表部分的内容会全部显示为NULL。
右外连接
# 右外连接
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;
与左连接相对应。
自连接
自连接就是一张表自己连接自己,且可以说一定会使用到别名。
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ... ;
举例,比如有员工表,一个公司的所有员工信息都在上面,现在想要查询每个员工的所属领导:
# emp就是员工表
select a.name , b.name from emp a , emp b where a.managerid = b.id;
公司总裁没有领导,managerid字段的值为空,想要显示总裁信息则可使用外连接进行自连接。
子查询
子查询又叫嵌套查询,即一个SELECT中再包含SELECT查询语句。
(子查询外部的语句还可以是INSERT / UPDATE / DELETE / SELECT 的任何一个。)
子查询的位置可以是:
1.WHERE后,作为条件的一部分
2.FROM后,作为被查询的一条表
3.SELECT之后 ,作为被查询的一列
当子查询出现在WHERE后作为条件时,还可以使用关键字:any/all
根据查询结果的不同,还可以将子查询分为:
1.结果为单个值 ,叫标量子查询
2.结果为一列 ,列子查询
3.结果为一行 ,行子查询
4.结果为多行多列 ,表子查询
标量子查询
子查询返回的结果是单个值(数字、字符串、日期等),这种子查询称为标量子查询。
常用的操作符:= <> > >= < <=
# 查询工资高于 所有职位为CLERK员工工资 的员工
SELECT * FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE job='CLERK');
列子查询
子查询返回的结果是一列,这种子查询称为列子查询
常用的操作符:IN 、NOT IN 、 ANY 、SOME 、 ALL
操作符 | 说明 |
---|---|
IN | 在指定的集合范围之内,多选一 |
NOT IN | 不在指定的集合范围之内 |
ANY | 子查询返回列表中,有任意一个满足即可 |
SOME | 与ANY等同 |
ALL | 子查询返回列表的所有值都必须满足 |
为了方便理解,下面是几个使用例子
# 查询所有 所属部门为 "SALES" 和 "ACCOUNTING" 的员工 的信息
select * from emp where dept_id in (select id from dept where name = 'SALES' or name = 'ACCOUNTING');# 查询工资高于 部门id为30的所有人工资 的员工信息
SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30);
行子查询
子查询返回的结果是一行,这种子查询称为行子查询
常用的操作符:= 、<> 、IN 、NOT IN
# 查询工作和工资 与MARTIN完全相同 的员工 的信息
SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename='MARTIN');
表子查询
子查询返回的结果是多行多列,这种子查询称为表子查询
常用的操作符(在WHERE中时):IN
举例:
现在有表:emp和dept
查询员工编号为7369的员工名称、员工工资、部门名称、部门地址
# 子查询生成的表需要使用别名
# 这种子查询需要与主语句进来联动
SELECT e.ename, e.sal, d.dname, d.loc FROM emp e, (SELECT dname,loc,deptno FROM dept) d WHERE e.deptno=d.deptno AND e.empno=7369;