目录
22.3当两张表进行连接查询时,没有任何条件的限制会发生什么现象?
23.5select后面出现的子查询(这个内容不需要掌握,了解即可!)
21,去除重复记录
注意:原表数据不会被修改,只是查询结果去重
去重需要使用一个关键字:distinct
mysql> select distinct job from emp;
+-------------------+
| job |
+-------------------+
| CLERK |
| SALESMAN |
| MANAGER |
| ANALYST |
| PRESIDENT |
+--------------------+
mysql> select ename,distinct job from emp;
这样写是错误的,语法错误
distinct只能出现在所有字段的最前方
//distinct出现在job,deptno两个字段之前,表示两个字段联合起来去重
mysql> select distinct job,deptno from emp;
+---------------------+-----------+
| job | deptno |
+--------------------+------------+
| CLERK | 20 |
| SALESMAN | 30 |
| MANAGER | 20 |
| MANAGER | 30 |
| MANAGER | 10 |
| ANALYST | 20 |
| PRESIDENT | 10 |
| CLERK | 30 |
| CLERK | 10 |
+-------------------+------------+
例:统计一下工作岗位的数量
mysql> select count(distinct job) from emp;
+---------------------------------+
| count(distinct job) |
+---------------------------------+
| 5 |
+---------------------------------+
distinct只能出现在所有字段的前方,但是可以用分组函数
22,连接查询
22.1什么是连接查询
从一张表中单独查询,称为单表查询
emp表和dept表联合起来查询数据,从emp表中取员工名字,从detp表中取部 门名字
这种跨表查询,多张表联合起来查询数据,被称为连接查询
22.2连接查询的分类
根据语法的年代分类
SQL92:1992年的时候出现的语法
SQL99:1999年的时候出现的语法
这里重点学习SQL99,这个过程简单演示一下SQL92的例子
根据表连接的方式分类
- 内连接
- 等值连接
- 非等值连接
- 自连接
- 外连接
- 左外连接(左连接)
- 右外连接(右连接)
- 全连接(不讲)
22.3当两张表进行连接查询时,没有任何条件的限制会发生什么现象?
例:查询每个员工所在部门名称?
mysql> select ename,dname from emp,dept;
这样会有14*4=56条记录
注意:
当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数,是两张表条数的乘积,这种现象被称为:笛卡尔现象。(笛卡尔发现的,这是一个数学现象。)
22.4怎么避免笛卡尔积现象?
连接时加条件,满足这个条件的记录被筛选出来!
mysql> select ename,dname from emp,dept where emp.deptno=dept.deptno;
上面的查询还是比较费时的,还有更简洁的做法,就是在select的字段前面加上表明限定,另外结合起别名就可以提高效率
//表起别名,很重要
mysql> select e.ename,d.dname from emp e,dept d where e.deptno=d.deptno;//SQL92 语法
思考:最终查询的结果条数是14条,但是匹配的过程中,匹配的次数减少了吗?
没有,还是56次,只不过进行了四选一,次数没有减少
注意:通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表连接的次数
22.5内连接之等值连接
例:查询每个员工所在的部门名称,显示员工名和部门名?
emp e和dept d表进行连接。条件是:e.deptno=d.deptno
SQL92语法:
select
e.ename,d.dname
from
emp e,dept d
where
e.deptno=d.deptno;
SQL92的缺点:
结构不清晰,表的连接条件和后期进一步筛选的条件,都放到了where 后面
SQL99语法:
select
e.ename,d.dname
from
emp e
(inner) join
dept d
on
e.deptno=d.deptno;
注:inner可以省略,带着inner可读性更好,一眼就能看出是内连接
SQL99的优点:
表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续 添加where
SQL99语法:
select
...
from
a
join
b
on
a和b连接条件
where
筛选条件
22.6内连接之非等值连接
例:找出每个员工的薪资等级,要求显示员工名,薪资,薪资等级?
select
e.ename,e.sal,s.grade
from
emp e
join
salgrade s
on
e.sal between s.losal and s.hisal;//条件不是一个等量关系,称为非等值连接
22.7内连接之自连接
例:查询员工的上级领导,要求显示员工名和对应的领导名
mysql> select empno,ename,mgr from emp;
技巧:一张表看成两张表
mysql> select a.ename as '员工名',b.ename as '领导名' from emp a join emp b on a.mgr=b.empno;//员工的领导编号=领导的员工编号
以上就是内连接中的自连接,技巧:一张表看成两张表
22.8外连接
例:查询员工的名称与对应的岗位
内连接(A和B连接,AB两张表没有主次关系,平等的):
mysql> select e.ename,d.dname from emp e join dept d on e.deptno=d.deptno;
内连接的特点:完成能够匹配上这个条件的数据查询出来
内连接是通过deptno把emp表和dept表连接起来,查询dept表和emp表deptno 相同的记录,但是如果要把dept表和emp表中的deptno不匹配的也找出来就要 用到外连接了
外连接(右外连接):
mysql> select e.ename,d.dname from emp e right join dept d on e.deptno=d.deptno;//在join前面加上right
外连接(左外连接)
mysql> select e.ename,d.dname from dept d left join emp e on e.deptno=d.deptno;//join前面加上left
带有right的是右外连接,又叫右连接
带有left的是左外连接,又叫左连接
任何一个右连接都有左连接的写法
任何一个左连接都有右连接的写法
right代表什么:表示将join关键字右边的这张表看成主表,主要是为了将这张表 的数据全部查询出来,捎带着关联查询左边的表
left代表什么:和right一样,表示将join左边的表看成主表
在外连接中,两张表连接产生了主次关系
join前面也可以加上outer,outer是可以省略的,上面就省略了,带着可读性强, 表示是外连接
注意:外连接的查询结果条数一定是>=内连接的查询结果条数
例:查询每个员工的上级领导,要求显示所有员工的名字和领导名
mysql> select a.ename as '员工名',b.ename as '领导名' from emp a left join emp b on a.mgr=b.empno;
22.9三张表,四张表怎么连接?
语法:
select
...
from
a
join
b
on
a和b的连接条件
join
c
on
a和c的连接条件
right join
d
on
a和d的连接条件
一条SQL中内连接和外连接可以混合,都可以出现!
例:找出每个员工的部门名称以及工资等级,要求显示员工名,部门名,薪资,薪资等级
mysql> select e.ename,e.sal,d.deptno,s.grade from emp e join dept d on e.deptno=d.deptno join salgrade s on e.sal between s.losal and s.hisal;
例:找出每个员工的部门名称以及工资等级,还有上级领导,要求显示员工名,领 导名,部门名,薪资,薪资等级
mysql> select e.ename,e.sal,d.deptno,s.grade,l.ename as '上级领导' from emp e join dept d on e.deptno=d.deptno join salgrade s on e.sal between s.losal and s.hisal left join emp l on e.mgr=l.empno;
23,子查询
23.1什么是子查询
select语句中嵌套select语句,被嵌套的select语句被称为子查询
23.2子查询都可以出现在哪里
select
...(select).
from
...(select).
where
...(select).
23.3where子句中的子查询
例:找出比最低工资高的员工姓名和工资?
mysql> select ename,sal from emp where sal>min(sal);
这样写不行,因为where子句中不能直接使用分组函数
实现思路:
第一步:查询最低工资是多少
mysql> select min(sal) from emp;
+---------------+
| min(sal) |
+--------------+
| 800.00 |
+---------------+
第二步:找出>800的
mysql> select ename,sal from emp where sal>800;
第三步:合并
mysql> select ename,sal from emp where sal>(select min(sal) from emp);
23.4from子句中的子查询
注意:from后面的子查询,可以将子查询的查询结果当做一张临时表(技巧)
例:找出每个岗位的平均工资的薪资等级
第一步:找出每个岗位的平均工资(按照岗位分组求平均值)
mysql> select avg(sal),job from emp group by job;
+-------------------+-------------------+
| avg(sal) | job |
+-------------------+-------------------+
| 1037.500000 | CLERK |
| 1400.000000 | SALESMAN |
| 2758.333333 | MANAGER |
| 3000.000000 | ANALYST |
| 5000.000000 | PRESIDENT |
+-------------------+-------------------+
t表
第二步:把以上的查询结果就当做一张真实存在的表t
mysql> select * from salgrade;//s表
+-----------+---------+------------+
| GRADE | LOSAL | HISAL |
+-----------+---------+-----------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-----------+---------+----------+
t表和s表进行表连接,条件:t表avg(sal) between s.losal and s.hisal;
mysql> select t.*,s.grade from (select avg(sal) as avgsal,job from emp group by job) as t join salgrade s on t.avgsal between s.losal and s.hisal;
23.5select后面出现的子查询(这个内容不需要掌握,了解即可!)
例:找出每个员工的部门名称,要求显示员工名,部门名?
mysql> select e.ename,(select d.dname from dept d where e.deptno=d.deptno) as dname from emp e;
//报错:ERROR 1242 (21000): Subquery returns more than 1 row
mysql> select e.ename,e.deptno,(select dname from dept) as dname from emp e;
注意:对于select后面的子查询来说,这个子查询只能一次返回1条结果,多于1 条,就报错了!
24,union合并查询结果集
例:查询工作岗位是MANAGER和SALESMAN的员工
mysql> select ename,job from emp where job='MANAGER' or job='SALESMAN';
下面用union实现
mysql> select ename,job from emp where job='MANAGER' union select ename,job from emp where job='SALESMAN';
union的效率要高一些。对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔 积,成倍的翻。。。
但是union可以减少匹配的次数,在减少匹配次数的情况下,还可以完成两个结果集的拼接
a连接b连接c
a 10条记录
b 10记录
c 10条记录
匹配次数:1000
a连接b一个结果:10*10 -->100次
a连接c一个结果:10*10 -->100次
使用union的话是:100次+100次=200次(union把乘法变成了加法运算)
union在使用的时候有注意事项吗?
//错误的:union在进行结果集合并的时候,要求两个结果集的列数相同
select ename,job from emp where job='MANAGER'
union
select ename from emp where job='SALESMAN';
//mysql可以,oracle语法严格,不可以,报错。
//要求:结果集合并时列和列的数据类型也要一致
select ename,job from emp where job='MANAGER'
union
select ename,sal from emp where job='SALESMAN';