MySQL:DQL查询

151 阅读13分钟

[内容时间:2021.09.01]

SQL语句的分类

DQL(数据查询语言 Data Query Language):查询语句,凡是select都是DQL

DML(数据操作语言 Data Manipulation Language):insert delete update,对表当中的数据进行增删改

DDL(数据定义语言 Data Definition Language):create drop alter,对表结构的增删改

TCL(事物控制语言 Transaction Control Lauguage):commit提交事务,rollback回滚事物(TCL中的T是Transaction)

DCL(数据控制语言 Data Control Language):grant授权、revoke撤销权限等

=================================================================

导入大量数据,使用source 命令,然后将文件拖拽进来就行,建议文件和相关路径别写中文名。 使用Navicat导入也可以

常用命令

  • 展示数据库:show databases;
  • 使用 / 指定某某数据库: use xxx;
  • 展示列表: show tables;
  • 查看当前数据库:select database();
  • 查看其他数据库中的表:show tables from +数据库名字
  • 查看表的结构: desc +表的名字
  • 查看建表语句: show create table +表名

查询(DQL)

这里开始使用SQL语句了(DQL)

前面的MySQL命令不是SQL语句,不具备通用性

简单查询

  • select +字段名1,字段名2,字段名3… from +表名,字段名换成星号那就是全选
  • 字段可以参与数学运算
  • select * from +表名(星号的方式不建议,因为效率较低,数据库要把星号转换成字段,这个代码最好别写在java程序当中,在dos窗口敲一敲也就算了)

怎么给查询结果的列重命名?

select +字段名1,字段名2 as 你想要的名字 from +表名

重命名想用中文怎么办?

  • 单引号

    select +字段名1,字段名2 as '你想要的名字' from +表名

  • 往后的版本似乎不用加单引号也可以了(我现在用8.0)

注意:标注SQL语句中要求字符串使用单引号括起来,虽然MySQL支持双引号,但尽量别用,因为不通用。

任何一条SQL语句不区分大小写,而且以分号结尾

条件查询

语法格式

select 字段1,字段… from 表名 where 条件;
比如查询工资等于5000的员工:
select ename from emp where sal=5000;
如果字段是varchar,那么要加单引号,后面版本可能不用
不等于:where sal<>5000
​
大于一千且小于五千:where sal>1000 and sal<5000;
第二种写法:where sal between 1100 and 5000;结果包含1100和5000,但切忌一定是左小右大。

执行顺序,先from,其次where,最后select

in相当于or,比方说where job='MANAGER' or job='SALESMAN'

in则这样子用:where job in ('MANAGER' , 'SALESMAN')

模糊查询like

语法格式

select ename from emp where like '%xxx';
select ename from emp where like '_';

%代表任意多个字符,_代表任意一个字符

找出名字带有O的

select ename from emp where like '%O%';

找出名字第二个字母是A的

select ename from emp where like '_A';

找出名字有下划线的

select ename from emp where like '%_%';

找出名字中最后一个字母是T的

select ename from emp where like '%T';

排序

举例 1:按照工资升序,找出员工名和薪资

语法格式:

select ename,sal from emp order by sal; //默认升序
select ename,sal from emp order by sal asc; //升序
select ename,sal from emp order by sal desc; //降序
===============================================
另一种写法:可以用数字表示,比如用第二列来比较,sal位于第二列
但是如果字段顺序发生改变,就不适用了,所以建议用上面的方法写死
select ename,sal from emp order by 2 desc;

复杂点的例子 例 2:工资降序排列,工资相同时按照名字升序排列

select ename,sal from emp order by sal desc,ename asc;

order by 后的字段,字段越靠前,起的主导作用越大!

比如例 2 中的sal权重比ename要大,sal相等时才按照ename排序,意思是只有前面字段相等的时候,后面的字段才会启用

例 3 :找出工作岗位是salesman的员工,并且要求按照工资的降序排

select ename,job,sal from emp where job='salesman' order by sal desc;

排序的order by优先级是靠后的。前面先经过from,然后到where

怎么验证?

select ename,sal as salary from emp order by salary;
只有前面那段代码执行了,salary这个别名才有,才能执行后面

分组函数(多行处理函数、聚合函数)

一共五个

  • 计数:count
  • 求和:sum
  • 平均值:avg
  • 最大值:max
  • 最小值:min

分组函数不能为空。自动忽略NULL,NULL不在统计范围内,所以不需要画蛇添足写个where is not null这个条件在后面(当然添加了也不会报错……)

特点是输入多行,输出一行。

分组函数不能出现在where子句中

count(*)和count(某个字段) 的区别

count(*):不是统计某个字段中数据的个数,二十统计总记录条数(和某个字段无关)

count(某个字段):表示统计某个字段中部位2NULL的数据总数量

单行处理函数

什么是单行处理函数?

输入一行,输出一行

注意:计算表达式时,如果有一个数值为空,则整条表达式结果为空。

select ename,(800+NULL) as yearsal from emp;
结果为空。

ifnull( ) 空处理函数

ifnull( 可能为null的数据,被当做什么处理 )

select ename,12*(sal + (ifnull(comm , 0))) as yearsal from emp;

group by 和 having

group by:按照某个字段或者某些字段进行分组

having:对分组之后的数据进行再次过滤

例 1:找出每个工作岗位的最高薪资

select max(sal),job from emp group by job;

注意:分组函数一般都会和group by联合使用,这也是为什么它被称为分组函数的原因。并且任何一个分组函数(count sum max min avg)都是在group by语句执行结束之后才会执行的。当一条SQL语句没有group by的话,整张表的数据会自成一组

例 2:找出每个部门不同工作岗位的最高薪资

select deptnp,job,max(sal) from emp group by deptno,job;

例 3:找出每个部门的最高薪资,要求显示薪资大于2900的数据

方法一:用where,效率高,注意where后面不能用分组函数。分组函数只能跟在 group by 后面
select deptno,max(sal) from emp where sal>2900 group by deptno;

方法二:用having,效率低
select deptno,max(sal) from emp group by deptno having max(sal)>2900;

例 4:找出每个部门的平均薪资,要求显示薪资大于2900的数据

这时where就搞不定了,要用having了
select deptno,avg(sal) from emp group by deptno having avg(sal)>2900;

注意:

当一条语句有group by的话,select后面只能跟分组函数 和参加分组的字段!

查询的执行顺序

select		5	过滤完之后查出来,查出来之后
	..	
from		1	先从里面查
	..	
where		2	经过where条件过滤之后
	..
group by	3	再分组,分组之后如果不满意
	..
having		4	再进行过滤
	..
order by	6	排序
	..
limit		7	选择取部分数据输出
	..

去除重复 distinct

  • distinct 只能出现在所有字段的最前面。
  • distinct 在最前面表示后面的所有字段联合去重

例 1:统计岗位的数量

select count(distinct job) from emp;

连接查询

什么是连接查询?

在实际开发中,大部分的情况都不是从单表中查询数据,一般都是多张表联合查询取出最终的结果。

如果将所有信息多存储到一张表中,数据将会存在大量重复,导致数据的冗余。

如:

stuno		stuname		class		classname
-------------------------------------------------------------
1		zhangsan	 1	       第一中学高一一班
2		lisi		 1	       第一中学高一一班
3		wangwu		 1	       第一中学高一一班

连接查询的分类

根据语法出现年代来划分:

SQL92(一些老的DBA有可能还在使用这种语法。DBA:DataBase Administrator,数据库管理员)

SQL99(比较新的语法)

根据表的链接方式划分:

内连接:

  • 等值连接
  • 非等值连接
  • 自连接

外连接:

  • 左外连接(左连接)
  • 右外连接(右连接)

全连接(这个不讲,很少用)

关于表的别名

使用连接表查询的时候建议使用表的别名

好处是:① 执行效率高。 ② 可读性好

执行效率高是因为两张表有可能有相同字段,有相同字段的数据库就会去两张表里面都找。如果指定了哪一张表,那就不用去别的表找,效率就大大提升了。

给表起别名方法如下:在表后面+空格+别名

select e.ename , d.dname from emp e, dept d;

这个是SQL92版本 ↑ ↑ ↑ ↑ ↑ ↑

笛卡尔积现象:

在表的连接查询方面有一种现象被称为笛卡尔积现象

当两张表进行连接查询的时候,没有任何条件进行限制,最终的查询结果条数是两张表记录条数的乘积。

怎么避免笛卡尔积现象?

当然是加条件过滤

思考:避免了笛卡尔积现象,会减少记录的匹配次数吗?

答:不会,次数还是两表字段之积,只不过显示的是有效记录。

连接查询之内连接的 :等值连接

最大的特点是:条件是等量关系

例 1:查询每个员工的部门名称,要求显示员工名和部门名

SQL92:(太老了,不用)

select e.ename,d.dname from emp e ,dept d where e.DEPTNO=d.DEPTNO;

SQL99:(常用)

select e.ename,d.dname from emp e join dept d on e.DEPTNO=d.DEPTNO;

语法是:…… A join B on 连接条件…… where(后面还可以加判断条件过滤……)

把原先的 逗号 , … where… 关键字改成了 join… on…
另外, join 之前可以加个 inner,变成 inner join,省略不影响结果,带上的话可读性好一些,一眼就知道是内连接。 

SQL99 将表的连接条件和where判断条件分离了,显得更有层次。

连接查询之内连接的 :非等值连接

最大的特点是:连接条件中的关系是非等量关系

例 1:找出每个员工的工资等级,要求现实员工名、工资、工资等级

select 
	e.ename,e.sal,s.grade 
from 
	emp e 
join 
	salgrade s 
on 
	e.sal between s.losal and hisal;

连接查询之内连接的 :自连接

最大的特点是:一张表看做两张表,自己连接自己

(MySQL比较难的查询就是自连接)

例 1:找出每个员工的上级领导,要求显示员工名和对应的领导名

select 
	a.ename as '员工',b.ename as '领导'
from 
	emp a
join 
	emp b
on 
	a.mgr=b.empno;

员工的领导编号,就是领导的员工编号,这个关系要搞清楚

连接查询之:外连接

最重要的特点是:主表的数据无条件的全部查出来

什么是外连接?和内连接有什么区别?

内连接:

  • 假设A和B 表进行连接,使用内连接的话,凡是A表和B表都能够匹配上的记录查询出来,匹配不上就不查了,比如KING的领导没有,那就不查了,这种就是内连接

    AB两张表没有主副之分,表表生而平等

外连接:

  • 假设A和B 表进行连接,使用外连接的话,AB两张表中有一张表是主表,一张表是副表,主要查询主表中的数据,捎带着查询副表。当副表中的数据没有和主表中的数据匹配上,副表自动模拟出NULL与之匹配
  • 左外连接:表示左边的是主表(左连接可以写成右连接,反之亦然)(左连接会有右连接的写法,反之亦然)
  • 右外连接:表示右边的是主表

实际开发中,外连接用得较多

如何区分内连接和外连接

内连接可以什么都不写

外连接一定要写个:left 或者 right

此外,内连接可以省略 inner 。外连接可以省略 outer

例 1:找出哪个部门没有员工

select
 	d.deptno,e.ename
from
	dept d
left join
	emp e
on
	d.deptno=e.deptno
where
	e.deptno is null;

三张表的连接

例 1:找出每一个员工的部门名称以及薪资等级

select
	e.ename, d.dname, s.grade
from
	emp e
join
	dept d
on
	e.deptno=d.deptno
join
	salgrade s
on
	e.sal between losal and hisal;
	

例 2:找出每一个员工的部门名称、薪资等级、上级领导

select
	a.ename, d.dname, s.grade, a.mgr
from
	emp a
left join
	emp b
on
	a.mgr=b.ename
join
	dept d
on
	a.deptno=d.deptno
join
	salgrade s
on
	a.sal between losal and hisal;

子查询

什么是子查询?

select 语句当中嵌套select 语句,被嵌套的select 语句都是子查询

子查询可以出现在哪里?

select
	……(select)
from
	……(select)
where
	……(select)

where字句中使用子查询

例 1:找出高于平均薪资的员工信息

select ename,sal from emp where sal > (select avg(sal) from emp);

from 后面嵌套子查询(重要)

例 1:找出每个部门平均薪水的薪资等级

第一步:找到每个部门的平均薪资
select avg(sal) as avgsal ,deptno from emp group by deptno;
第二步:把第一步看成是个临时表,然后跟salgrade 表连接
select
	t.*, s.grade
from
	(select avg(sal) as avgsal ,deptno from emp group by deptno) t
join
	salgrade s
on
	t.avgsal between s.losal and s.hisal;

例 2:找出每个部门薪资等级的平均值

第一步:找出每个员工的薪水等级
select 
	e.ename, s.grade 
from 
	emp e 
join 
	salgrade s 
on 
	e.sal between s.losal and s.hisal;
第二步:基于以上结果继续按照deptno 分组,求grade平均值
(其实我感觉是一步到位的。。)
select
	e.deptno, avg(s.grade) as avgGrade
from 
	emp e
join 
	salgrade s
on
	e.sal between s.losal and s.hisal
group by
	e.deptno;

select 后面嵌套子查询

例 1:找出每个员工所在的部门名称

方法一:上面写过,用内连接
select e.ename,d.dname from emp e join dept d on e.deptno=d.deptno; 
方法二:用select后面嵌套子查询(可读性差,知道这么回事就行)
select
	e.ename,(select d.dname from dept d where e.deptno=d.deptno) as dname
from
	emp e;

union关键字

作用和 or ,in 大同小异,都是将两个范围内的字段拼接在一起,不同点是执行结果是同类分类好的。因为是先筛选第一行,再筛选第二行……最后拼接在一起

还有 in,or 解决不了的问题!

比如两张毫不相干的表的连接

语法格式:要求 select 后面的字段数量一样。而且表的名称取决于第一行
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 |
+--------+----------+

limit (重点)

以后分页查询全靠它!

  • limit 是MySQL 特有的,其他数据库没有。
  • limit 取结果集中的部分数据,这是他的作用
  • limit 是SQL语句最后执行的一环!

语法格式:

limit startIndrx,length ---> 意思是 从哪里开始,截取长度是几
举例:取出工资前五的员工
select ename,sal from emp order by sal desc limit 0,5;
若只取前五个还可以这样子:把 0省略
select ename,sal from emp order by sal desc limit 5;

通用的标准分页SQL

每页显示3条记录:

第一页:0,3

第二页:3,3

第三页:6,3

……

  • 每页显示pageSize条记录
  • 第pageNo页的 limit :(pageNo - 1) * pageSize , pageSize

用Java 代码表示

int pageNo = 2;//页码2
int pageSize = 10;//每页显示10条
limit (pageNo - 1) * pageSize , pageSize