MySQL概述及DQL
数据库就是用来存储数据的,之前的数据要么是直接存储在程序的变量中直接操作,要么是直接存储在文件中利用文件流来操作。但是呢,这些都不是存储数据的最佳方式,存储数据的最佳方式就是今天的重头戏:数据库啦!
废话不多说。
数据库有MySQL、Oracle,DB2,sql server等等,Java中最常用的就是MySQL,因为它轻量级,并且是开源的,最重要的是它免费,支持白嫖啊!
(MySQL是一个数据库管理系统,但是大家好像都习惯称为数据库了。)
先介绍一下DBMS,DB,SQL的区别:
- DBMS:数据库管理系统。
- DB:数据库。
- SQL:结构化查询语言,一种标准的语法。
它们的关系是:DBMS通过执行SQL语句去操作DB中的数据。
再来看,什么是表?表是一种结构化的文件。用来存储数据
表就是有行有列吧,就和Excel中的一样。像下面这种:
学号 | 姓名 | 性别 |
---|---|---|
001 | Tom | 男 |
不陌生吧,MySQL中的表也是一样的,有行有列:
- 行,又称为记录(data);
- 列,又称为字段(column)。
1.SQL语句的分类
SQL语句主要分为五大类:
- DML数据操作语言:主要包含数据库中表数据的插入、删除、更新,即(insert、delete、update);
- DQL数据查询语言:主要包含数据库中表数据的查询。(重头戏!);
- DDL数据定义语言:主要是对数据库中表的操作,如创建表、删除表、修改表,即(create、drop、alter);
- DCL数据控制语言:主要是对数据库用户的授权和撤销权限,即(grant、revoke);
- TCL事务控制语言:事务控制语言,主要是对数据库中的事务的操作,事务的提交和回滚,即(commit、rollback)。
最最最重要的就是DQL了!TCL也很重要!
(此处忽略MySQL的安装,可问度娘)
2.MySQL命令
#创建数据库
create database 数据库名;
#使用数据库
use 数据库名;
#查询当前数据库
select database();
#查看有哪些数据库
show database;
#查看当前数据库中有哪些表(先使用数据库)
show tables;
#查看表的结构(查看表的字段、数据类型、长度、约束等等)
desc 表;
#查看创建表的语句
show create table 表名;
#删库跑路
drop 数据库名;
3.DQL(insert)
最最最重要的DQL来啦!
DQL不区分大小写。#、--、/**/都为注释。
字段查询
- 查询整个表的数据
select * from tb_name;
- 查询某个字段
select column_name from tb_name;
- 查询多个字段
select column_name1,column_name2,... from tb_name;
给字段取别名
select column_name1 as 别名,... from tb_name;
条件查询
select column_name1,column_name2,... from tb_name where 条件;
where条件支持的运算符:
= | 等于 |
---|---|
<>或者!= | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
and | 和,用于拼接多个条件,只有全部符合条件的数据才是结果 |
or | 或,用于拼接多个条件,只要满足一个条件即可 |
in | 或的升级,in(value1,value2),只要值为()中任意一个值即可 |
not | 否定(如is not null,not in) |
between...and... | 在什么之间,前小后大,支持数字和字符 |
like | 模糊查询,%代表任意个字符,_代表任意一个字符 |
is null | 空,NULL为空,代表没有数据(区别于空串'') |
去重
去重:去掉结果中重复的值,关键字为distinct。
select distinct column_name,... from tb_name where ...;
注意:distinct只能放在所有字段的最前方,支持多个字段去重,如果(distinct 字段1,字段2):意思为只有字段1和字段2的值都相等才会当作是重复的值。
排序
ASC(升序)、DESC(降序)。
默认升序。
select column_name,... from tb_name where... order by 字段名,... ASC或DESC
以上的执行顺序为:先from,再where,再select,再order by。
证明:可以对select后的字段使用别名,结果出来是别名,说明是select先执行,order by后执行。
可以多个字段同时进行排序,但是以前面的字段为主导,只有前面的字段值一样无法比较出大小时,才会使用后面的字段。
分组函数
分组函数有:
MAX(最大值),MIN(最小值),COUNT(记录总条数)、SUM(数据总和)、AVG(数据平均值)
select 分组函数(column_name),... from tb_name where...;
第一个重点:分组函数会忽略NULL值。可以使用if null(可能为null值的数据,当为null值时用什么替换null值)来解决NULL值计算带来的问题。
第二个重点:分组函数不能出现在where子句中。上面说过,where子句比select先执行,在where中使用分组函数就相当于用了还不存在的东西,肯定是不行的。
第三:count(*)为表的总记录条数,与字段无关。count(字段)为某个字段的条数,并且会忽略NULL值。
分组函数可以组合使用,即使用多个分组函数。
- group by按某个字段进行分组
select column_name,分组函数(column_name),... from tb_name where... group by column_name;
以上的执行顺序为:from->where->group by->select。
当没有group by时,整个表会自成一组。
第一个重点:group by一般和分组函数联合使用,并且一定在分组函数前执行。
第二个重点:当一条sql语句中有group by时,select后面只能跟group by后出现的字段和分组函数。
虽然出现了不是group by后面的字段不会报错,但是没有意义。Oracle该种情况就会直接报错。
多个字段可以联合使用,先按前面的字段分组,再按后面的字段进行分组。
- having条件过滤
having和group by是一组的,只有有了group by才可以使用having,可以单独使用group by,但是不能单独使用having。
select column_name,分组函数(column_name),... from tb_name where... group by column_name having 条件;
以上的执行顺序为:from->where->group by->having->select。
where先进行第一层的过滤,再分组之后,如果还需要进行筛选的话,就使用having。having的效率比where低,如果可以使用where的话,尽量使用where。
select (5)
xxx
from (1)
xxx
where (2)
xxx
group by (3)
xxx
having (4)
xxx
order by
xxx; (6)
数字为执行顺序。
连接查询
在实际的开发中,不可能只有一个表,而表与表之间,也常常都是有关联的。
(如果把所有的数据都放在一个表中的话,可能会有很多多余的数据,会造成表的数据十分的庞大。)
所以在实际的开发中,往往对应的需求都不是单表查询,而是查询多个表,即联表查询,即连接查询。
连接查询的分类:
- 内连接
- 等值连接;
- 非等值连接;
- 自连接。
- 外连接
- 左外连接(左连接);
- 右外连接(右连接)。
先看几张表:
emp:员工表
字段:员工编号empno,员工姓名ename,员工职位job,员工上级领导编号mgr,员工入职日期hiredate,员工工资sal,
员工补贴comm,员工部门编号depyno;
dept:部门表
字段:部门编号deptno,部门名称dname,部门所在地址loc;
salgrade:工资等级表
字段:等级grade,最低工资losal,最高工资hisal。
连接查询的关键字为join,表1 join 表2(join 表3...) on 条件。可同时连接多个表。
笛卡尔积现象
两张表连接查询,没有任何的条件,结果数目为两张表总条数的乘积,这个现象称为笛卡尔积现象。
- 内连接-等值连接
#如:查询每位员工所在的部门名称
#员工姓名在员工表中,部门名称在部门表中,所以需要联表查询
#可以通过员工表中的员工部门编号去部门表中查询
SELECT e.ename,d.dname FROM emp e INNER JOIN dept d ON e.deptno = d.deptno;
给表使用别名的好处:因为两张表中可能有一样的字段,所以如果没有起别名的话,就会两张表都去查看是否有这个字段,降低效率,如果起了别名,指定了是哪张表,就只需要去指定的那张表中找,就可以提高效率了;并且两张表中有相同的数据,会产生混淆。
- 内连接-非等值查询
#如:查询每位员工的薪资等级
#员工姓名在员工表中,薪资等级在工资等级表中
SELECT e.ename,s.grade FROM emp e JOIN salgrade s ON e.`SAL` BETWEEN s.losal AND hisal;
内连接使用inner join...on,inner可以省略。
- 内连接-自连接
把一张表看作两张表。
#如:查询每个员工的领导表,要求显示员工姓名和领导
#因为员工信息在emp表中,领导信息也在emp表中,所以emp既是员工表,又是领导表
#要先找到每位员工的领导编号,再通过领导编号去emp表中领导查对应的名字
SELECT e.ename '员工',t.ename '领导' FROM emp e JOIN (SELECT empno,ename FROM emp) t ON e.mgr= t.empno;
(这个可能需要多理解一下)
内连接与外连接的区别
内连接没有主表和副表之分,两个表的地位是一样的,内连接查询的是表之间能够匹配上的数据。
外连接有主表和副表之分,
左连接即左边的为主表,右连接即右边的表为主表(左连接有右连接的写法,右连接也有左连接的写法)
主要查询主表,捎带着查询副表,必须保证主表的完整,如果副表没有与主表匹配的数据,会自动填充NULL。
像上述查询每个员工的领导,因为有一个人肯定是没有领导的,如果是使用内连接,就会丢失掉这个大boss的信息,所以必须要使用外连接查询
- 左连接
#如:还是上面的查询每位员工领导的例子
SELECT e.ename '员工',t.ename '领导' FROM emp e LEFT OUTER JOIN (SELECT empno,ename FROM emp) t ON e.mgr= t.empno;
outer可省略。
- 右连接
#将上述例子改成右连接
SELECT e.ename '员工',t.ename '领导' FROM (SELECT empno,ename FROM emp) t RIGHT JOIN emp e ON e.mgr= t.empno;
多看看表中的数据和关系就能比较好的理解了(虽然本人也是菜鸟一枚)
三张表连接查询
#如:找出每一个员工的部门名称和薪资等级
#员工名称在员工表,部门名称在部门表,薪资等级在薪资表
#所以需要三张表连接查询
#先员工表和部门表查出员工姓名和部门名称,再员工表和和薪资等级表连接查询得出员工的薪资等级。
SELECT e.ename,d.dname,s.grade FROM emp e LEFT JOIN dept d ON e.`DEPTNO` = d.`DEPTNO`
LEFT JOIN salgrade s ON e.`SAL` BETWEEN s.`LOSAL` AND s.`HISAL`;
子查询
子查询就是使用多个select,其实上述连接查询的例子中,就已经使用了子查询了,在from后面。
子查询有三种形式:
- 在select后面;
- 在from后面;
- 在where后面。
- select子查询
#如:找出每个员工所在的部门名称,要求显示员工名称和部门名称(使用join更简单,但是这里为了介绍select后面跟select语句)
SELECT e.ename,(SELECT d.dname FROM dept d WHERE e.deptno = d.deptno) AS deptname FROM emp e;
- from子查询
使用最多。
#如上述的内外连接。
- where子查询
#找出高于平均薪资的员工(切记:where后面不能直接跟分组函数!)
SELECT ename FROM emp WHERE sal >(SELECT AVG(sal) FROM emp);
union
union是连接查询,可以将查询结果拼接起来:
#找出工作岗位是CLERK和SALESMAN的员工(可以使用or、in,也可以使用union)
(SELECT ename FROM emp WHERE job = 'CLERk') UNION (SELECT ename FROM emp WHERE job = 'SALESMAN');
注意:mysql不区分大小写,但是,表中的数据严格区分大小写!
分页
分页很重要!
limit 该页开始的下标,该页的条数;
#下标从0开始,若下标是0,可以省略
#如:找出员工表中前五条数据
SELECT * FROM emp LIMIT 5;
#找出员工表中第6-10条数据
SELECT * FROM emp LIMIT 5,5;
所以这里涉及到了一个计算的问题,如何根据给定的页数和条数计算出起始下标(在实际开发中,都是以参数的形式传递页码的)
limit (pageNo-1)* pageSize, pageSize (pageNo为页码,pageSize为每页条数)
以上涉及到的执行顺序总结:
select (5)
xxx #*、字段、去重、分组函数、字段别名
from (1)
xxx #单表、多表、连表join
where (2)
xxx #支持的运算符 = <>或!= > < >= <= and or in not (is null) like between...and...
group by (3)
xxx #单字段、多字段
having (4)
xxx #与group by联合使用,接条件
order by (6)
xxx #ASC DESC
limit (7)
xxx #分页