注意:原表数据不会被修改,只是查询结果去重。 去重需要使用一个关键字:distinct mysql> select distinct job from emp; +-----------+ | job | +-----------+ | CLERK | | SALESMAN | | MANAGER | | ANALYST | | PRESIDENT | +-----------+
重点注意
// 这样编写是错误的,语法错误。 // distinct只能出现在所有字段的最前方。 mysql> select ename,distinct job from emp; // 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 | +-----------+--------+
select count(distinct job) from emp; +---------------------+ | count(distinct job) | +---------------------+ | 5 | +---------------------+
从一张表中单独查询,称为单表查询。 emp表和dept表联合起来查询数据,从emp表中取员工名字,从dept表中取部门名字。 这种跨表查询,多张表联合起来查询数据,被称为连接查询。
根据语法的年代分类: SQL92:1992年的时候出现的语法 SQL99:1999年的时候出现的语法 我们这里重点学习SQL99.(这个过程中简单演示一个SQL92的例子) 根据表连接的方式分类: 内连接: 等值连接 非等值连接 自连接 外连接: 左外连接(左连接) 右外连接(右连接) 全连接(不讲)
案例:查询每个员工所在部门名称? mysql> select ename,deptno from emp; +--------+--------+ | ename | deptno | +--------+--------+ | SMITH | 20 | | ALLEN | 30 | | WARD | 30 | | JONES | 20 | | MARTIN | 30 | | BLAKE | 30 | | CLARK | 10 | | SCOTT | 20 | | KING | 10 | | TURNER | 30 | | ADAMS | 20 | | JAMES | 30 | | FORD | 20 | | MILLER | 10 | +--------+--------+ mysql> select * from dept; +--------+------------+----------+ | DEPTNO | DNAME | LOC | +--------+------------+----------+ | 10 | ACCOUNTING | NEW YORK | | 20 | RESEARCH | DALLAS | | 30 | SALES | CHICAGO | | 40 | OPERATIONS | BOSTON | +--------+------------+----------+ 两张表连接没有任何条件限制: select ename,dname from emp, dept; +--------+------------+ | ename | dname | +--------+------------+ | SMITH | ACCOUNTING | | SMITH | RESEARCH | | SMITH | SALES | | SMITH | OPERATIONS | | ALLEN | ACCOUNTING | | ALLEN | RESEARCH | | ALLEN | SALES | | ALLEN | OPERATIONS | ... 56 rows in set (0.00 sec) 14 * 4 = 56 当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数,是 两张表条数的乘积,这种现象被称为:笛卡尔积现象。(笛卡尔发现的,这是 一个数学现象。)
连接时加条件,满足这个条件的记录被筛选出来! select ename,dname from emp, dept where emp.deptno = dept.deptno; select emp.ename,dept.dname from emp, dept where emp.deptno = dept.deptno; // 表起别名。很重要。效率问题。 select e.ename,d.dname from emp e, dept d where e.deptno = d.deptno; //SQL92语法。 +--------+------------+ | ename | dname | +--------+------------+ | CLARK | ACCOUNTING | | KING | ACCOUNTING | | MILLER | ACCOUNTING | | SMITH | RESEARCH | | JONES | RESEARCH | | SCOTT | RESEARCH | | ADAMS | RESEARCH | | FORD | RESEARCH | | ALLEN | SALES | | WARD | SALES | | MARTIN | SALES | | BLAKE | SALES | | TURNER | SALES | | JAMES | SALES | +--------+------------+ 思考:最终查询的结果条数是14条,但是匹配的过程中,匹配的次数减少了吗? 还是56次,只不过进行了四选一。次数没有减少。 注意:通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表的 连接次数。
SQL99语法: select e.ename,d.dname from emp e join dept d on e.deptno = d.deptno; //inner可以省略(带着inner可读性更好!!!一眼就能看出来是内连接) select e.ename,d.dname from emp e inner join dept d on e.deptno = d.deptno; // 条件是等量关系,所以被称为等值连接。
案例:找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
select e.ename, e.sal, s.grade from emp e inner join salgrade s on e.sal between s.losal and s.hisal; +--------+---------+-------+ | ename | sal | grade | +--------+---------+-------+ | SMITH | 800.00 | 1 | | ALLEN | 1600.00 | 3 | | WARD | 1250.00 | 2 | | JONES | 2975.00 | 4 | | MARTIN | 1250.00 | 2 | | BLAKE | 2850.00 | 4 | | CLARK | 2450.00 | 4 | | SCOTT | 3000.00 | 4 | | KING | 5000.00 | 5 | | TURNER | 1500.00 | 3 | | ADAMS | 1100.00 | 1 | | JAMES | 950.00 | 1 | | FORD | 3000.00 | 4 | | MILLER | 1300.00 | 2 | +--------+---------+-------+
案例:查询员工的上级领导,要求显示员工名和对应的领导名?
select a.ename as '员工名', b.ename as '领导名' from emp a join emp b on a.mgr = b.empno; //员工的领导编号 = 领导的员工编号 +--------+--------+ | 员工名 | 领导名| +--------+--------+ | SMITH | FORD | | ALLEN | BLAKE | | WARD | BLAKE | | JONES | KING | | MARTIN | BLAKE | | BLAKE | KING | | CLARK | KING | | SCOTT | JONES | | TURNER | BLAKE | | ADAMS | SCOTT | | JAMES | BLAKE | | FORD | JONES | | MILLER | CLARK | +--------+--------+
以上就是内连接中的:自连接,技巧:一张表看做两张表。
select e.ename,d.dname from emp e right join dept d on e.deptno = d.deptno; right代表什么:表示将join关键字右边的这张表看成主表,主要是为了将 这张表的数据全部查询出来,捎带着关联查询左边的表。 在外连接当中,两张表连接,产生了主次关系。
select e.ename,d.dname from dept d left join emp e on e.deptno = d.deptno;
带有right的是右外连接,又叫做右连接。 带有left的是左外连接,又叫做左连接。 任何一个右连接都有左连接的写法。 任何一个左连接都有右连接的写法。
思考:外连接的查询结果条数一定是 >= 内连接的查询结果条数? 正确。
select a.ename as '员工名', b.ename as '领导名' from emp a left join emp b on a.mgr = b.empno; +--------+--------+ | 员工名 | 领导名 | +--------+--------+ | SMITH | FORD | | ALLEN | BLAKE | | WARD | BLAKE | | JONES | KING | | MARTIN | BLAKE | | BLAKE | KING | | CLARK | KING | | SCOTT | JONES | | KING | NULL | | TURNER | BLAKE | | ADAMS | SCOTT | | JAMES | BLAKE | | FORD | JONES | | MILLER | CLARK | +--------+--------+
语法: select ... from a join b on a和b的连接条件 join c on a和c的连接条件 right join d on a和d的连接条件 一条SQL中内连接和外连接可以混合。都可以出现!
select e.ename,e.sal,d.dname,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; +--------+---------+------------+-------+ | ename | sal | dname | grade | +--------+---------+------------+-------+ | SMITH | 800.00 | RESEARCH | 1 | | ALLEN | 1600.00 | SALES | 3 | | WARD | 1250.00 | SALES | 2 | | JONES | 2975.00 | RESEARCH | 4 | | MARTIN | 1250.00 | SALES | 2 | | BLAKE | 2850.00 | SALES | 4 | | CLARK | 2450.00 | ACCOUNTING | 4 | | SCOTT | 3000.00 | RESEARCH | 4 | | KING | 5000.00 | ACCOUNTING | 5 | | TURNER | 1500.00 | SALES | 3 | | ADAMS | 1100.00 | RESEARCH | 1 | | JAMES | 950.00 | SALES | 1 | | FORD | 3000.00 | RESEARCH | 4 | | MILLER | 1300.00 | ACCOUNTING | 2 | +--------+---------+------------+-------+
select e.ename,e.sal,d.dname,s.grade,l.ename 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; +--------+---------+------------+-------+-------+ | ename | sal | dname | grade | ename | +--------+---------+------------+-------+-------+ | SMITH | 800.00 | RESEARCH | 1 | FORD | | ALLEN | 1600.00 | SALES | 3 | BLAKE | | WARD | 1250.00 | SALES | 2 | BLAKE | | JONES | 2975.00 | RESEARCH | 4 | KING | | MARTIN | 1250.00 | SALES | 2 | BLAKE | | BLAKE | 2850.00 | SALES | 4 | KING | | CLARK | 2450.00 | ACCOUNTING | 4 | KING | | SCOTT | 3000.00 | RESEARCH | 4 | JONES | | KING | 5000.00 | ACCOUNTING | 5 | NULL | | TURNER | 1500.00 | SALES | 3 | BLAKE | | ADAMS | 1100.00 | RESEARCH | 1 | SCOTT | | JAMES | 950.00 | SALES | 1 | BLAKE | | FORD | 3000.00 | RESEARCH | 4 | JONES | | MILLER | 1300.00 | ACCOUNTING | 2 | CLARK | +--------+---------+------------+-------+-------
select语句中嵌套select语句,被嵌套的select语句称为子查询。
select ..(select). from ..(select). where ..(select).
案例:找出比最低工资高的员工姓名和工资? select ename,sal from emp where sal > min(sal); ERROR 1111 (HY000): Invalid use of group function where子句中不能直接使用分组函数。
实现思路: 第一步:查询最低工资是多少 select min(sal) from emp; +----------+ | min(sal) | +----------+ | 800.00 | +----------+ 第二步:找出>800的 select ename,sal from emp where sal > 800; 第三步:合并 select ename,sal from emp where sal > (select min(sal) from emp); +--------+---------+ | ename | sal | +--------+---------+ | ALLEN | 1600.00 | | WARD | 1250.00 | | JONES | 2975.00 | | MARTIN | 1250.00 | | BLAKE | 2850.00 | | CLARK | 2450.00 | | SCOTT | 3000.00 | | KING | 5000.00 | | TURNER | 1500.00 | | ADAMS | 1100.00 | | JAMES | 950.00 | | FORD | 3000.00 | | MILLER | 1300.00 | +--------+---------+
注意:from后面的子查询,可以将子查询的查询结果当做一张临时表。(技巧)
案例:找出每个岗位的平均工资的薪资等级。
第一步:找出每个岗位的平均工资(按照岗位分组求平均值) select job,avg(sal) from emp group by job; +-----------+-------------+ | job | avgsal | +-----------+-------------+ | ANALYST | 3000.000000 | | CLERK | 1037.500000 | | MANAGER | 2758.333333 | | PRESIDENT | 5000.000000 | | SALESMAN | 1400.000000 | +-----------+-------------+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; select t.*, s.grade from (select job,avg(sal) as avgsal from emp group by job) t join salgrade s on t.avgsal between s.losal and s.hisal; +-----------+-------------+-------+ | job | avgsal | grade | +-----------+-------------+-------+ | CLERK | 1037.500000 | 1 | | SALESMAN | 1400.000000 | 2 | | ANALYST | 3000.000000 | 4 | | MANAGER | 2758.333333 | 4 | | PRESIDENT | 5000.000000 | 5 | +-----------+-------------+-------+
(这个内容不需要掌握,了解即可!!!)
案例:找出每个员工的部门名称,要求显示员工名,部门名? select e.ename,e.deptno,(select d.dname from dept d where e.deptno = d.deptno) as dname from emp e; +--------+--------+------------+ | ename | deptno | dname | +--------+--------+------------+ | SMITH | 20 | RESEARCH | | ALLEN | 30 | SALES | | WARD | 30 | SALES | | JONES | 20 | RESEARCH | | MARTIN | 30 | SALES | | BLAKE | 30 | SALES | | CLARK | 10 | ACCOUNTING | | SCOTT | 20 | RESEARCH | | KING | 10 | ACCOUNTING | | TURNER | 30 | SALES | | ADAMS | 20 | RESEARCH | | JAMES | 30 | SALES | | FORD | 20 | RESEARCH | | MILLER | 10 | ACCOUNTING | +--------+--------+------------+ //错误:ERROR 1242 (21000): Subquery returns more than 1 row select e.ename,e.deptno,(select dname from dept) as dname from emp e; 注意:对于select后面的子查询来说,这个子查询只能一次返回1条结果, 多于1条,就报错了。!
案例:查询工作岗位是MANAGER和SALESMAN的员工? select ename,job from emp where job = 'MANAGER' or job = 'SALESMAN'; select ename,job from emp where job in('MANAGER','SALESMAN'); +--------+----------+ | ename | job | +--------+----------+ | ALLEN | SALESMAN | | WARD | SALESMAN | | JONES | MANAGER | | MARTIN | SALESMAN | | BLAKE | MANAGER | | CLARK | MANAGER | | TURNER | SALESMAN | +--------+----------+ select ename,job from emp where job = 'MANAGER' union select ename,job from emp where job = 'SALESMAN'; +--------+----------+ | ename | job | +--------+----------+ | JONES | MANAGER | | BLAKE | MANAGER | | CLARK | MANAGER | | ALLEN | SALESMAN | | WARD | SALESMAN | | MARTIN | SALESMAN | | TURNER | 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'; +--------+---------+ | ename | job | +--------+---------+ | JONES | MANAGER | | BLAKE | MANAGER | | CLARK | MANAGER | | ALLEN | 1600 | | WARD | 1250 | | MARTIN | 1250 | | TURNER | 1500 | +--------+---------+
limit作用:将查询结果集的一部分取出来。通常使用在分页查询当中。 百度默认:一页显示10条记录。 分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差。 可以一页一页翻页看。
limit怎么用呢? 完整用法:limit startIndex, length startIndex是起始下标,length是长度。 起始下标从0开始。 缺省用法:limit 5; 这是取前5. 按照薪资降序,取出排名在前5名的员工? select ename,sal from emp order by sal desc limit 5; //取前5 select ename,sal from emp order by sal desc limit 0,5; +-------+---------+ | ename | sal | +-------+---------+ | KING | 5000.00 | | SCOTT | 3000.00 | | FORD | 3000.00 | | JONES | 2975.00 | | BLAKE | 2850.00 | +-------+---------+
注意:mysql当中limit在order by之后执行!!!!!
案例
*** 取出工资排名在[3-5]名的员工? select ename,sal from emp order by sal desc limit 2, 3; 2表示起始位置从下标2开始,就是第三条记录。 3表示长度。 +-------+---------+ | ename | sal | +-------+---------+ | FORD | 3000.00 | | JONES | 2975.00 | | BLAKE | 2850.00 | +-------+---------+ *** 取出工资排名在[5-9]名的员工? select ename,sal from emp order by sal desc limit 4, 5; +--------+---------+ | ename | sal | +--------+---------+ | BLAKE | 2850.00 | | CLARK | 2450.00 | | ALLEN | 1600.00 | | TURNER | 1500.00 | | MILLER | 1300.00 | +--------+---------+
每页显示3条记录 第1页:limit 0,3 [0 1 2] 第2页:limit 3,3 [3 4 5] 第3页:limit 6,3 [6 7 8] 第4页:limit 9,3 [9 10 11] 每页显示pageSize条记录 第pageNo页:limit (pageNo - 1) * pageSize , pageSize public static void main(String[] args){ // 用户提交过来一个页码,以及每页显示的记录条数 int pageNo = 5; //第5页 int pageSize = 10; //每页显示10条 int startIndex = (pageNo - 1) * pageSize; String sql = "select ...limit " + startIndex + ", " + pageSize; } 记公式: limit (pageNo-1)*pageSize , pageSize
select ... from ... where ... group by ... having ... order by ... limit ... 执行顺序? 1.from 2.where 3.group by 4.having 5.select 6.order by 7.limit..