DQL-Data Query Language(数据查询语言)
简单查询(查询单个字段)
- 格式:
select 字段名 from 表名;
//字段名和表名都是标识符,select和from都是关键字
//强调:对于sql语句来说是通用的,sql不区分大小写,以‘;’结尾
// 中文别名需要用引号引起来
查询多个字段
//使用英文下逗号隔开
select 字段名,字段名 from 表名;
查询所有字段
-
可以把每个字段都写上
select a,b,c,d,e,f... from 表名;
-
可以使用
*
select * from 表名;
缺点:(会先把'*'转化为字段名,然后再按照第一种方式查询)
- 效率低
- 可读性差
在实际开发中不建议。
-
查询年薪
select ename, sal*12 from emp;
结论:字段可以参与加减乘除运算
-
查询时起别名(使用‘as')
select deptno, dname as deptname from dept;
//'as'可以省略,注意:别名之间不能有空格
select deptno, dname deptname from dept;
//如果非要在别名中加' '空格,可以使用引号(''或""都可以)
select deptno,dname 'dept name' from dept;
//注意:在所有的数据库中,字符串统一使用单引号括起来,单引号是标准,双引号在oracle数据库中用不了。但是在mysql中可以使用
注意:
-
只是将显示的查询结果列名显示为deptname,原列名不改变还是叫:dname
-
在所有的数据库中,字符串统一使用单引号括起来,单引号是标准,双引号在oracle数据库中用不了。但是在mysql中可以使用
记住:
- select语句是永远都不会进行修改操作的。(因为只负责查询)
条件查询
-
什么是条件查询
- 不是将表中所有数据都查出来。是查询出符合条件的。
-
语法格式
select 字段1,字段2,字段3... from 表名 where 条件;
-
都有哪些条件
// = 等于 // 查询薪资等于800的员工 select empno,ename from emp where sal = 800; // 查询叫smith的员工 select empno,ename,sal from emp where ename = 'smith'; // <> 或 != 不等于 // 查询薪资不等于800的员工 select empno,ename from emp where sal != 800; select empno,ename from emp where sal <> 800; // < 小于 // 查询薪资小于2000的员工 select empno,ename from emp where sal < 2000; // <= 小于等于 // 查询薪资小于等于2000的员工 select empno,ename from emp where sal <= 2000; // > 大于 // 查询薪资大于2000的员工 select empno,ename from emp where sal > 2000; // >= 大于等于 // 查询薪资大于等于2000的员工 select empno,ename from emp where sal >= 2000; // between ... and ... 两个值之间,等同于 >= and <= // 查询薪资在2450和3000之间的员工信息? 包括2450和3000 select empno,ename,sal from emp where sal between 2450 and 3000; select empno,ename,sal from emp where sal >= 2450 and sal <= 3000; // is null 为空 // 查询津贴为空的员工信息 select empno,ename,sal,comm from emp where comm is null; // and 并且 //查询工作岗位是manager,并且工资大于2500的员工信息 select empno,ename,job,sal from emp where job = 'manager' and sal > 2500; // or 或者 //查询工作岗位是manager 和salesman的员工 select empno,ename,job from emp where job = 'manager' or job = 'salesman'; //查询工资大于2500,并且部门编号为10或20部门的员工 select deptno,ename,sal from emp where sal > 2500 and (deptno = 10 or deptno = 20); // in 包含,相当于多个or(not in 不在这个范围) //查询工作岗位时manager和salsman的员工 select empno,ename,job from emp where job = 'manager' or job = 'salesman'; select empno,ename,job from emp where job in('manager','salesman'); //查询薪资等于800和5000的员工信息 select empno,ename,job,sal from emp where sal in(800,5000); // like 称为模糊查询,支持%或下划线匹配 // %匹配任意个字符 // 下划线,一个下划线只匹配一个字符 //(%是一个特殊字符,_也是一个特殊字符) // 找出名字中含有o的? select ename from emp where ename like '%o%'; // 找出名字中以 t 结尾的 select ename from emp where ename like '%t'; // 找出名字中以k开始的 select ename from emp where ename like 'k%'; // 找出名字中第二个字母是a的 select ename from emp where ename like '_a%'; // 找出名字中第三个字母是r的 select ename from emp where ename like '__r%' // 找出名字中有"_"的 // \转义字符 select name from t_student where name like '%\_%';
注意:
- 在使用between...and...的时候要遵循左小右大的原则
- between..and...是闭区间
- 在数据库中null不能使用等号进行衡量。需要使用
is null
。因为数据库中的null代表什么也没有,他不是一个值,所以不能使用等号衡量。 - and 和 or同时出现时,and优先级较高。如果想让or先行,需要加上小括号
- 如果不确定优先级,可以加上小括号
- in不是一个区间。in后面跟的是具体的值
- 找出名字中有“_”的数据,可以使用转义字符''
排序
// 查询所有员工薪资,排序
select ename,sal from emp order by sal;
// 查询所有员工薪资,指定降序
select ename,sal from emp order by sal desc;
// 查询所有员工薪资,指定升序
select ename,sal from emp order by sal asc;
// 查询员工名字和薪资,要求按照薪资升序,如果薪资一样的胡啊,再按照名字升序排列
select ename,sal from emp
order by
sal asc, ename asc;//sal在前,起主导地位
//根据字段的位置也可以排序
//按照查询结果的第2列sal排序
select ename,sal from emp order by 2;
//找出工资在1250到3000之间的员工信息,要求按照薪资降序排列
//执行顺序from-->where-->select-->order by(排序总是在最后)
select
ename,sal
from
emp
where
sal between 1250 and 3000
order by
sal desc;
- 排序,默认为升序
- 不建议在开发中根据字段的位置进行排序,因为不健壮,列的顺序很容易发生改变
分组查询(非常重要)
-
什么是分组中查询
- 在实际的应用中,可能有这样的需求,需要先进行分组,然后对每一组的数据进行操作,这个时候就需要进行分组查询
//将之前的关键字全部组合在一起 select ... from ... where ... group by ... order by //执行顺序from->where->group by->select->order by //找出每个工作岗位的工资和 //先从emp表中查询数据,根据job字段进行分组,然后对每一组数据进行sum(sal) select sum(sal) from emp group by job; //找出每个部门的最高薪资 //按照部门编号分组,求每一组的最大值 select deptno,max(sal) from emp group by deptno; //找出每个部门不同岗位的最高薪资 select job,deptno,max(sal) from emp group by deptno, job; //找出每个部门最高薪资,要求显示最高薪资大于3000的 //第一步:找出每个部门最高薪资 select deptno,max(sal) from emp group by deptno; //第二步:要求显示最高薪资大于3000 // having 可以对分完组之后的数据进一步过滤 select deptno,max(sal) from emp group by deptno having max(sal) > 3000; select deptno,max(sal) from emp where sal > 3000 group by deptno; //找出每个部门平均薪资高于2500的 select deptno,avg(sal) from emp group by deptno having avg(sal) > 2500; select ... from ... where ... group by ... having ... order by ... //找出每个岗位的平均薪资,要求显示平均薪资大于1500的,除manager岗位之外,要求按照平均薪资降序拍 select job, avg(sal) as acgsal from emp where job <> 'MANGER' group by job having avg(sal) > 1500 order by avgsal desc;
说明:
-
分组函数不能直接使用在where后面
因为分组函数在使用的时候必须先分组之后才能使用。
where执行的时候,还没有分组,所以where后面不能出现分组函数
-
在一条select语句中,如果有group by语句的话,
select后面只能跟:参加分组的字段,以及分组函数
其他的一律不能跟
-
having不能单独使用。having不能代替where,having必须与group by联合使用
-
能使用where过滤掉的,尽量使用
-
where和having,优先选择where,,然后再选择having
-
执行顺序:
- from
- where
- group by
- having
从某张表中查询数据,
先经过where条件筛选出有价值的数据
对这些有价值的数据进行分组
分组之后可以使用having继续筛选
select查询出来。
最后排序输出
连接查询(最重要)
-
什么是连接查询
- 从一张表中单独查询,称为单表查询
- emp表和dept表联合起来查询数据,从emp表中取员工名字,从dept表中取部门名字。这种跨表查询,多张表联合起来查询数据,被称为连接查询。
-
当两张表进行连接查询,没有任何限制的时候,最终查询结果条数,是两张表条数的乘积,这种现象被称为:笛卡尔积现象
-
怎么避免笛卡尔积现象?
- 连接时加条件,满足这个条件的记录被筛选出来
select ename,dname from emp,dept where emp.deptno = dept.deptno;
最终查询结果条数是14条,但是匹配的过程中,匹配的次数没有减少,只不过进行了四选一
注意:
- 通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免笛卡尔积现象
-
连接查询的分类
- 根据语法的年代分类;
- SQL92:1992年的时候出现的语法
- SQL99:1999年的时候出现的语法
- 根据表的连接方式分类:
-
内连接(A和B连接,AB两表没有主次关系)
-
特点:完成能够匹配上这个条件的数据查询出来
-
等值连接
- 条件是等量关系,所以是等值连接
// 查询每个员工所在部门名称,显示员工名和部门名 select e.ename,d.dname from emp e, dept d where e.deptno = d.deptno;//(SQL92的语法) select e.ename,d.dname from emp e join dept d on e.deptno = d.deptno;
说明:
-
SQL92缺点:结果不清晰,表的连接条件,和后期进一步筛选的条件都放where后面。
-
SQL99优点:表连接的条件是独立的,连接之后,如果还需要进一步筛选,再往后继续添加where条件
select ... from a inner join //inner可以省略,带着inner可读性更好,一看就是内连接 b on a和b的连接条件 where 筛选条件
-
非等值连接
- 条件不是一个等量关系,称为非等值连接
//找出每个员工的薪资登记,要求显示员工名、薪资薪资等级 select e.ename, e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;
-
自连接
- 技巧:一张表看做两张表
// 查询员工的上级领导,要求显示员工名和对应领导名 // 技巧:一张表看程两张表 select a.ename as '员工名', b.ename as '领导名' from emp a join emp b on a.mgr = b.empno;//员工的领导编号 = 领导的员工编号
-
-
外连接
-
在外连接当中,两张表连接,产生了主次关系
-
右外连接(右连接)
select e.ename,d.dname from emp e right outer join dept d on e.deptno = d.deptno;
- right表示将join关键字右边的这张表看成主表,主要是为了将这张表的数据全部查询出来,捎带着关联查询左边的表
-
左外连接(左连接)
select e.ename,d.dname from emp e left outer join dept d on e.deptno = d.deptno;
- 任何一个右连接都有左连接的写法
- 任何一个左连接都有右连接的写法
- outer可以省略,带着可读性强
-
说明:
-
外连接的查询结果条数一定是 >= 内连接的查询结果条数
//查询每个员工的上级领导,要求显示所有员工的名字和领导名 select a.ename as '员工名',b.ename as '领导名' from emp a left join emp b on a.mgr = b.empno;
-
-
-
全连接(几乎很少有)
-
三张表,四张表怎么连接?
-
语法:
select ... from a join b on a和b的连接条件 join c on a和c的连接条件 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; //找出每个员工的部门名称以及工资等级,还有上级领导,要求显示员工名、领导名、部门名、薪资、薪资等级 select a.ename as '员工名',b.ename as '领导名',d.dname, a.sal,s.grade from emp as a left join emp as b on a.mgr = b.empno join dept as d on a.deptno = d.deptno join salgrade as s on a.sal between s.losal and s.hisal order by s.grade asc, a.sal desc;
-
-
子查询
-
select语句中嵌套select语句,被嵌套的select语句称为子查询。
-
出现位置
select ...(select) from ...(select) where ...(select)
- where子句中的子查询
//找出比最低工资高的员工姓名和工资 //第一步:查询最低工资 select min(sal) from emp; //第二步:找出>800的 select ename,sal from where sal > 800; //第三步:合并 select ename,sal from emp where sal > (select min(sal) from emp);
-
from子句中的子查询
//找出每个岗位的平均薪资的薪资等级 //第一步:找出每个岗位的平均工资(按照岗位分组求平均值) select job,avg(sal) from emp group by job; //第二步:克服心理障碍,把以上的查询结果当成一张真是存在的表t select t.*,s.grade from t join salgrade as s on 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 as s on t.avgsal between s.losal and s.hisal;
- 注意:from后面的子查询,可以将子查询的查询结果当做一张临时表(技巧)
-
select后面出现的子查询
//找出每个员工的部门名称,要求显示员工名,部门名 select e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;
注意:
- 对于select后面的子查询来说,这个子查询只能返回1条结果,多于1条就会报错
-
-
union合并查询结果集
- 要求两结果集的列数相同
- union :得到两个查询结果的并集,并且自动去掉重复行。不会排序
- union all:得到两个查询结果的并集,不会去掉重复行。也不会排序
- intersect:得到两个查询结果的交集,并且按照结果集的第一个列进行排序
- minus:得到两个查询结果的减集,以第一列进行排序
- oracle要求结果集合并时,列和列的数据类型也要相同
//查询工作岗位是mananager和salesman的员工 //方法一: select ename,job from emp where job = 'manager' or job = 'salesman'; //方法二: select ename,job from emp where job in('manager', 'salesman'); //方法二: select ename,job from emp where job = 'manager' union select ename,job from emp where job = 'salesman';
-
union的效率要高些。对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。。。
-
但是union可以减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接
-
union把乘法变成了加法运算
-
limit取部分数据
- 完整用法:limit startIndex, length
- startIndex是起始下标,length是长度
- 起始下标从0开始
- 缺省用法:limit 5;//这是取前5条
将查询结果集的一部分取出来,通常使用在分页查询当中。
分页的作用是为了提高用户的体验,因为一次全部都查出来,用户体验差,
可以一页一页的翻页看。
//按照薪资降序,取出排名在前5的员工 select ename,sal from emp order by sal desc limit 5; //取出工资在3到5名的员工 select ename,sal from emp order by sal desc limit 2,3; //取出工资排名在[5-9]名的员工 select ename,sal from emp order by sal desc limit 4, 5;
注意:
- mysal中limit在order by 之后执行!!!!!
- 完整用法:limit startIndex, length
-
分页
每页显示3条记录
第1页:limit 0,3
第2页:limit 3,3
第3页:limit 6,3
第4页:limit 9,3
每页显示pageSize条记录
第pageNo页:limit (pageNo - 1) * pageSize , pageSize
//DQL语句大总结
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..