[内容时间: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