MySQL数据库
MySQL是一个**关系型数据库管理系统****,**由瑞典[MySQL AB](https://baike.baidu.com/item/MySQL AB/2620844) 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型和大型网站的开发都选择 MySQL 作为网站数据库。
(以上介绍来源于百度)
什么是数据库?什么是数据库管理系统?什么是SQL?它们之间的关系是什么?
数据库,全称为DataBase,简称DB
按照一定格式存储数据的一些文件的组合。
文件中存储了具有特定格式的数据。
数据库管理系统,全称为DataBaseManagementSystem,简称DBMS
专门用来管理数据库中的数据的系统,可以对数据库中的数据进行增删改查等操作。
常见的DBMS:MySQL,Oracle,MS SqlServer,DB2,sybase等
SQL,全称为Structure Query Language(结构化查询语言)
程序员编写SQL语句,然后通过DBMS来执行SQL语句,最终完成对数据库中数据的操作
SQL是一套标准,SQL能在大部分数据操作系统中都可以使用,如SQL,DB2,ORACLE等
三者的关系:
使用DBMS=》执行SQL=》操作DB
需要先安装MySql数据库管理系统,然后学习SQL语句的写法,然后使用DBMS,执行SQL,完成数据的操作。
DBA:Data Base Administrator 数据库管理员
CRUD:(增删改查)
create 创建
retrieve 查询
update 更新
delete 删除
端口号:
端口号port是任何一个软件/应用都会有的,端口号是应用的唯一代表
端口号通常和IP地址在一块,IP地址是用来定位计算机的,端口号port是用来定位某台计算机上的某个应用/服务的
在同一台计算机上,端口号不能重复,具有唯一性
Mysql数据库启动的时候,这个服务占用的默认端口是3306
(可以在my.ini里面更改)
字符集:
设置MYSQL数据的字符集为UTF8
服务名:
最好不要更改,默认是mysql
环境变量:
将bin目录加入到环境变量path中
设置管理员的密码:
用户名默认root不能改,然后设置超级管理员的密码
设置密码的同时,可以激活root账户远程访问
激活远程访问:
激活:root账户可以远程登录
不激活:root账户只能在本机上使用
【MySQL卸载方法】https://blog.csdn.net/qq_45776730/article/details/123258877
注意:每个版本可能不一致,按照个人需求和实际卸载
此电脑–>右键–>管理–>服务和应用程序–>服务–>mysql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CNSmNYjb-1690357313819)(MySQL.assets/image-20220727160202370.png)]
mysql的服务默认是“自动启动”的状态,只有启动了mysql的服务,mysql才能使用。
可以右键更改启动方式
启动
net start mysql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6k3rWJa-1690357313824)(MySQL.assets/image-20220727163947608.png)]
注:start后面跟的是你配置的mysql服务的服务名称,若在之前更改了服务名称的,这里需要更改为对应的名称
如配置的服务名称为 mysql80 则应该是: net start mysql80
关闭
net stop mysql
使用Mysql安装目录下bin目录下的mysql.exe打开,就可以进行登录
如果将mysql配置到了环境变量,就可以直接执行mysql命令
mysql -u root -p
回车
然后输入你的密码
exit
或者
quit
Access denied for user ‘root’@‘localhost’ (using password: YES)
【解决Mysql:ERROR 1045 (28000):Access denied for user ‘root‘@‘localhost‘ (using password: NO)的方法】https://www.jb51.net/article/250474.htm
以下命令行代码均在管理员权限下运行:
net stop mysql
注意:mysql8.0无法直接在my.ini中添加–skip-grant-tables来进行跳过密码验证,需要使用命令行的方式
mysqld -console --skip-grant-tables --shared-memory
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iue8BTkm-1690357313829)(MySQL.assets/image-20220727171008963.png)]
在上述步骤之后,再打开一个管理员模式运行的cmd.exe
不需要通过net start mysql
打开mysql服务
然后输入
mysql -u root -p
直接回车,就可以进入mysql界面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tnDOHJ7i-1690357313834)(MySQL.assets/image-20220727171126037.png)]
use mysql; (使用mysql数据表)
update user set authentication_string='' where user='root';(将密码置为空)
quit; (然后退出Mysql)
1.关闭前两个cmd窗口(一定要关闭!);
2.在第三个窗口中输入代码;
然后输入
cd D:\mysql-8.0.19-winx64\bin (此处输入自己电脑上的安装目录)
mysql -u root -p
(此处会显示输入密码,直接回车就好了,第四步我们已经将他置为空了)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';(By 后面跟的字符串就是你想要更新的密码)
quit(退出mysql)
mysql -u root -p
(输入新密码,再次登录)
记录时间:2022-7-27-17:13 --好像是老问题了,之前一直没有改正过来,正好在复习的时候将其改正,一定要跟着步骤慢慢来。
注意:所有命令都需要用分号结尾(登录除外
命令不区分大小写(也可以大小写混用)
不见分号不执行
\c 指令用来终止
ctrl+c 退出MYSQL
mysql -u root -p 回车
输入密码
exit;
show databases;
use [数据库名称];
create database [数据库名称];
//然后查看数据库
show databases;
show tables;
select version()
select database();
数据库中的表是以表格的方式来表示数据的
任何一张表都有行和列:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nEIvR8pY-1690357313839)(MySQL.assets/image-20220727174653459.png)]
每行(row)称为一个记录(数据)。
每列(column)称为一个字段。
数据类型:字符串、数字、日期等。
约束:对每个字段进行约束,有不同的规则对每个字段唯一性等建立约束
SQL语句有很多,根据功能和作用进行分类,更方便记忆和使用。
【数据库中DQL、DML、DDL、DCL、TCL概述】https://blog.csdn.net/weixin_44169484/article/details/119255935
DQL 数据查询语言Data Query Language
select 查询
DML 数据操作语言Data Manipulation Language
insert 插入
delete 删除(数据)
update 更新
DDL 数据定义语言Data Definition Language
create 创建
drop 删除(表、数据库、约束、触发程序等)
alter 修改
Truncate语句:清空表里的数据。
DCL 数据控制语言Data Control Language
grant 给与权限
revoke 回收权限
TCL 事务控制语言Transaction Control Language
commit 事务提交
rollback 事务回滚
Savepoint语句:为回退而存在,个数没有限制,与虚拟机中快照类似。savepoint是事务中的一点。用于取消部分事务,当结束事务时,会自动的删除该事务中所定义的所有保存点
Set transaction语句:设置事务的各种状态,比如只读、读/写、隔离级别
xxx.sql这种文件被称为SQL脚本文件。
脚本文件中编写的是大量的SQL语句。
#我们执行SQL脚本文件时,其中的所有SQL语句都会被执行。
批量的执行SQL语句时,可以采用SQL脚本文件。
MySQL中执行脚本文件的方法:
在DOS窗口中输入
source + 脚本路径
或者是通过工具进行导入
当需要导入大量的SQL数据的时候,可以使用导入SQL脚本的形式进行写入。
注意:
路径中不能带有中文、空格
注意观察文件内是否有关于创建数据库的语句,若没有,需要手动创建并选择数据库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b0ekhbBW-1690357313843)(MySQL.assets/image-20220729143806393.png)]
然后执行 source + SQL脚本文件路径 如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ibRSMmM-1690357313848)(MySQL.assets/image-20220729143920722.png)]
导入成功之后,查看表:
show tables;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BgYaSKCQ-1690357313852)(MySQL.assets/image-20220729144134866.png)]
然后查看表内的数据:
select * from dept; //查看dept表内的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFNjXGBL-1690357313857)(MySQL.assets/image-20220729144212701.png)]
select * from emp; //查看emp表中的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZrWYviZI-1690357313861)(MySQL.assets/image-20220729144307147.png)]
select * from salgrade; //查看salgrade表中的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9QvbvVn-1690357313866)(MySQL.assets/image-20220729144359838.png)]
使用 desc + 表名; //查询表的结构
分别是 字段名 类型 是否可以为空 主键约束 默认数值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXJ7LgB8-1690357313870)(MySQL.assets/image-20220729145451258.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Dx5h2zN-1690357313875)(MySQL.assets/image-20220729145515221.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UoOXKO2t-1690357313879)(MySQL.assets/image-20220729145524244.png)]
select 字段名 from 表名;
select 和 from 是关键字
字段名 和 表名 是标识符
对于大部分数据库管理软件来说SQL结构查询语言是通用的,所有的SQL语句都应该以“ ; ”分号结尾,且SQL语句不区分大小写(Windows系统下)。(Linux 系统默认是要区分的,需要在my.ini中加入lower_case_table_name=1可以设置为不区分大小写)
使用逗号隔开
例如:查询deptno和dname两个字段
select deptno , dname from dept;
第一种方式:把所有的字段写上
第二种方式:用*号代替所有字段(会把 “ * ”号转为字段名,效率低,可读性差,且无法按照自己想要的顺序进行排序)
select * from dept;
使用 原字段名 as 你想要更改成的名称(注意,若是中文字符,则需要使用单引号进行包裹)
注:只是将表头显示的列名改为对应的名称,原字段名不会发生改变,因为select语句只负责查询。
select deptno as '序号',dname as NAME from dept;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzb9KHfC-1690357313884)(MySQL.assets/image-20220729174241425.png)]
可以省略 as 关键字,使用空格进行分割,MYSQL依然会将你后面那个名称作为别名,如:
select deptno '序号',dname NAME from dept;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RNLPupB2-1690357313889)(MySQL.assets/image-20220729174549719.png)]
假设起别名的时候,别名中有空格怎么办?
解决方法:
使用单引号进行包裹(双引号在部分数据库中不支持,如Oracle,但是在mysql中可以使用)
select deptno as 'maka 序号',dname 'baka 名称' from dept;
可以使用数学表达式对数据进行计算
select ename, sal*12 as '年薪' from emp;
select ename, sal/12 as '年薪' from emp;
select ename, sal+12 as '年薪' from emp;
select ename, sal+12 as '年薪' from emp;
使用select时,可以若select没有的字段时,就会报错
如:
mysql> select abc from emp;
ERROR 1054 (42S22): Unknown column 'abc' in 'field list'
但是若select 的目标是一个字符串,那么就会将这个字符串按照表记录的数量,打印对应数量的行,详细如下所示:
mysql> select 'abc' as '表中的abc' from emp;
+-----------+
| 表中的abc |
+-----------+
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
| abc |
+-----------+
14 rows in set (0.00 sec)
同理,1000也被视为字符串
select 1000 as '表中的abc' from emp;
把查询结果去除重复记录【distinct】
distinct只能出现在所有字段的最前方。
distinct出现在job,deptno两个字段之前,表示两个字段联合起来去重。
select distinct job from emp;
select distinct job,deptno from emp;
//可以对分组函数使用distinct
select distinct round(avg(sal),2),job from emp group by job;
select job , destinct deptno from emp;//错误
查询符合条件的数据
select 字段名 from 表名 where 条件
= 等于
<> 或者 != 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
between ... and ... 两个值之间,等同于 >= and <=
is null 判断是否为空 (is not null)判断是否不为空
and 并且
or 或者
in 包含 相当于多个 or (not in 不在这个范围中)
not 取非,主要用于 is 或者 in 中
like 模糊查询,使用各种通配符进行模糊匹配
% 或者 _ 匹配
% 匹配任意多个字符
_ 下划线只匹配一个字符
例举:
查询薪资小于等于5000的所有员工的编号和名称
select empno as '编号', ename as '名称',sal as '薪资' from emp where sal <= 5000;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BVRiVnjF-1690357313893)(MySQL.assets/image-20220729180724662.png)]
‘ = ’ 符号也可以使用在字符串对比上
比如查询姓名为‘smith’的所有信息
select * from emp where ename = 'smith';
查询大于2000小于6000的sal
select empno as '编号',ename as '名称',sal as '薪资' from emp where sal >= 2000 and sal <= 6000;
或者
select empno as '编号',ename as '名称',sal as '薪资' from emp where sal between 2000 and 6000;
数据库中 null 不能使用 ‘ = ‘ 进行比对,需要使用 is null 进行比对
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资' from emp where comm is null;
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资' from emp where comm is not null;
用于两个条件语句的连接,意为 条件A和条件B 同时满足
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资' from emp where job = 'Manager' and sal > 2000;
用于两个条件语句的连接,意为 条件A和条件B 满足其中一个
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where job = 'Manager' or job = 'salesman';
工资大于2500,且部门编号为10或者20的员工。
select * from emp where sal > 2500 and deptno = 10 or deptno = 20;
and 语句的优先级比 or 的优先级高,不论位置
所以以上语句表示的是 工资大于2500和编号为10的 员工,或者编号为20的员工。
所以应该使用括号将低优先级的or进行包裹,让其优先级变高。
select * from emp where sal > 2500 and (deptno = 10 or deptno = 20);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8b2Tavv0-1690357313897)(MySQL.assets/image-20220730084233185.png)]
绿色为正确结果,红色为错误的结果。
包含,相当于多个 or
例如:查询工作岗位是Manager 和 salesMan 的员工:
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where job = 'Manager' or job = 'salesman';
用 in 的方式
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where job in ('Manager' , 'salesman');
注意:in 不是区间,是具体值,相当于job = ‘具体值’ or job = ‘具体值’;
具体同上, 只不过是相反,不等于这几个值的意思。
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where job not in ('Manager' , 'salesman');
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pWa2t3gc-1690357313902)(MySQL.assets/image-20220730084902404.png)]
模糊查询
支持%或者_匹配
%匹配多个字符,_匹配一个字符
例如:
查询名字中含有 ‘ t ’ 的:
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where ename like '%t%';
名字中第二位是 ’ m ’ 的:
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where ename like '_m%';
若需要找 名字中带有下划线的:
使用 ’ \ ’ 转义字符,若名字中找带有 ‘ \ ’ 的:/ \
select empno '编号',ename '姓名',sal '薪资',comm '额外薪资',job '工作' from emp where ename like '\_%';
排序总是在最后,如
select … from … where … order by …
默认排序是升序,也就是默认带有order by [字段名] asc
select empno '编号',ename as '姓名',sal as '薪资' from emp order by sal (后面默认带一个asc表示为升序);
降序 desc
select empno '编号',ename as '姓名',sal as '薪资' from emp order by sal desc;
如:薪资升序的同时,名称按照A-Z的顺序排
使用 ’ , ’ 分隔不同的
select empno '编号',ename as '姓名',sal as '薪资' from emp order by sal asc , ename asc;
排序出来的结果,首先是按照第一个条件进行排序的,然后值相同的情况下,按照第二个条件进行排序。
在mysql 中,我们经常会对一个字段进行排序,若不是中文字段则可以使用order by ColumnName,但进行中文字段排序,对汉字的排序结果往往都是错误的。 这是因为order by是根据对应字符的ASCII码排序。
如要实现按照中文拼音的排序,不想改变数据库结构的话,简单的做法是,在sql语句内加入CONVERT 函数即可。
select * from table order by CONVERT(列名 USING gbk);
https://blog.csdn.net/weixin_44948683/article/details/105842081
根据查询出来结果的第一个字段进行排序:(不建议,列顺序容易发送变化,且没有健壮性。)
select empno '编号',ename as '姓名',sal as '薪资' from emp order by 1 asc;
程序健壮性就是你的程序在遇到异常的情况下还能运行或者给予用户友好的提示。所以写代码的时候尽量考虑周全。
该做异常处理的就做异常处理,性能和正确性比起来一文不值。
寻找工资在2000到3000之间,且job不为Manager,按照工资的大小降序排序,相同的薪资以名称升序排序。
select ename as '姓名',sal as '薪资' from emp where sal between 2000 and 3000 order by sal desc,ename asc;
函数名 | 作用 |
---|---|
lower | 转换小写 |
upper | 转换大写 |
length | 取长度 |
substr | 取子串的长度 |
str_to_date | 字符串转为日期 |
date_format | 格式化日期 |
format | 设置千分位 |
round | 四舍五入 |
rand() | 生成随机数 |
ifnull | 可以将null转换成一个具体值 |
数据处理函数又被称为单行处理函数
单行处理函数的特点是:一个输入对应一个输出
和单行处理函数相对的是:多行处理函数(多个输入对应一个输出,例如统计所有员工的工资总和,select sum(sal) as ‘总薪资’ from emp;
例如将显示的所有名称转为小写:
select lower(ename) as '姓名' from emp order by ename asc;
将所有的字母转为大写
select upper(ename) as '姓名' from emp order by ename asc;
方法体:substr(被截取的字符串, 起始下标, 截取的长度)
substr的起始下标从1开始
select substr(ename,1,2) as '截取之后的ename' from emp;
例子:找出员工名字第一个字母是A的员工信息?
第一种:模糊查询
select ename from emp where ename like 'A%';
第二种:substr方式
select ename from emp where substr(ename,1,1) = 'A';
concat() 字符串的拼接
select concat(substr(upper(ename),1,1),lower(substr(ename,2,length(ename)))) as '首字母大写' from emp;
获取字符串的长度
select ename as '名称', length(ename) as '名称的长度' from emp;
去除前后空白
例如 前端传过来的数据中前后带有空白,此时就需要使用trim
select ename from emp where ename = trim(' king ');
但是中间的空格就不会去除
select ename from emp where ename = trim(' k i n g ');
结果:Empty set (0.00 sec)
把字符串转为日期
select * from emp where hiredate=str_to_date(1981-02-20);
drop table if exists t_user;
create table if not exists t_user(
user_id int,
user_name varchar(30),
user_birth date
);
#插入数据时:
insert into t_user values(1,'makabaka','1990-10-1');
#执行成功....
Query OK, 1 row affected (0.01 sec)
#但是如果插入时,没有按照对应的以 年-月-日 来插入,如下:
insert into t_user values(1,'makabaka','10-1-1990');
#结果:
ERROR 1292 (22007): Incorrect date value: '10-1-1990' for column 'user_birth' at row 1
#执行错误,因为'19990-10-1'不是一个date类型的数据
语法格式:
str_to_date(日期的字符串,日期的格式)
mysql 的日期格式:
%Y 年
%m 月
%d 日
%h 时
%i 分
%s 秒
insert into t_user values(2,'wuxidixi',str_to_date('10-1-1990','%m-%d-%Y'));
#此时:
Query OK, 1 row affected (0.00 sec)
#执行成功
str_to_date函数可以把字符串varchar转为日期date类型的数据
通常使用在insert into数据插入方面,因为某些字段会被定义为date类型的数据
需要通过该函数将字符串转为date类型
但是若插入时,字符串匹配了 [ 年-月- 日 ] 格式,就不用使用该函数。
了解一下:
#java中的日期格式
yyyy-HH-dd HH:mm:ss SSS
将date类型转换成一定格式的varchar类型字符串
用法:
date_format(日期类型的数据,需要显示的日期格式)
一般用在查询日期方面,设置展示的日期格式。
select user_id as '编号',user_name as '姓名',date_format(user_birth,'%m/%d/%Y') as '生日' from t_user;
#结果:
+------+----------+------------+
| 编号 | 姓名 | 生日 |
+------+----------+------------+
| 1 | makabaka | 10/01/1990 |
| 2 | wuxidixi | 10/01/1990 |
+------+----------+------------+
2 rows in set (0.00 sec)
#select查询date型的数据时,会自动将date转为varchar类型显示在dos命令窗口中,并且采用磨人的mysql日期格式:'%Y-%m-%d'
数字的格式化,给数字添加千分位,第二个参数是保留的小数位数,且函数自带四舍五入
select ename as '员工名',format(sal,2) as '工资' from emp;
#结果:
+--------+----------+
| 员工名 | 工资 |
+--------+----------+
| SMITH | 800.00 |
| ALLEN | 1,600.00 |
...
| FORD | 3,000.00 |
| MILLER | 1,300.00 |
+--------+----------+
14 rows in set (0.00 sec)
#当第二个参数为0时,表示取整
SELECT FORMAT(100.7654,3);//四舍 100.765
SELECT FORMAT(100.7655,3);//五入 100.766
四舍五入
round(数字, 需要保留的小数位数)
select round(1234.567,0) as 'result' from dept;
结果为:
+--------+
| result |
+--------+
| 1230 |
| 1230 |
| 1230 |
| 1230 |
+--------+
4 rows in set (0.01 sec)
第二个参数若为负数,则就往前四舍五入(以小数点的位置,负数为往前,往前进行四舍五入
如:
select round(1234.567,-1) as 'result' from dept;
结果为:
+--------+
| result |
+--------+
| 1230 |
| 1230 |
| 1230 |
| 1230 |
+--------+
4 rows in set (0.00 sec)
若数字为1235.666,此时再去取-1
mysql> select round(1235.666,-1) as 'result' from dept;
结果为:
+--------+
| result |
+--------+
| 1240 |
| 1240 |
| 1240 |
| 1240 |
+--------+
4 rows in set (0.00 sec)
可以看到,此时是按小数点的前一位,也就是10位作为四舍五入的位置。
生成一个范围0-1的随机数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hwAma4Cr-1690357313907)(MySQL.assets/image-20220730180017319.png)]
生成100以内的随机数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzkBehNQ-1690357313911)(MySQL.assets/image-20220730184244969.png)]
空处理函数,专门处理空数据
在所有数据中,只要有null参与运算,则最终结果一定为null
如:计算年薪
select ename as '姓名', (sal + comm) * 12 as '年薪' from emp;
结果为:
+--------+----------+
| 姓名 | 年薪 |
+--------+----------+
| SMITH | NULL |
| ALLEN | 22800.00 |
| WARD | 21000.00 |
| JONES | NULL |
| MARTIN | 31800.00 |
| BLAKE | NULL |
| CLARK | NULL |
| SCOTT | NULL |
| KING | NULL |
| TURNER | 18000.00 |
| ADAMS | NULL |
| JAMES | NULL |
| FORD | NULL |
| MILLER | NULL |
+--------+----------+
14 rows in set (0.00 sec)
为了避免这个现象,则需要使用ifnull函数。
用法:
ifnull(数据, 若为空时赋的值)
还是以上的例子,如果补助为null时,把补助设置为0
select ename as '姓名', (sal + ifnull(comm,0)) * 12 as '年薪' from emp;
结果为:
+--------+----------+
| 姓名 | 年薪 |
+--------+----------+
| SMITH | 9600.00 |
| ALLEN | 22800.00 |
| WARD | 21000.00 |
| JONES | 35700.00 |
| MARTIN | 31800.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
14 rows in set (0.00 sec)
例子:当员工工作岗位为Manager的时候,工资上涨10%,当工作岗位为Salesman的时候,工资上调50%
select ename as '名称',job as '工作',sal as'薪资',
(case job
when 'Manager' then sal*1.1
when 'salesman' then sal*1.5
else sal end) as '真实薪资'
from emp where sal > 1000;
TimestampDiff(间隔类型,前一个日期,后一个日期)
TimestampDiff(YEAR,hiredate,now())
间隔类型:
second 秒
minute 分钟
hour 小时
day 天
week 星期
month 月
quarter 季度
year 年
多行处理函数的特点是,输入多行,最终输出一行
名称 | 作用 |
---|---|
count | 计数 |
sum | 求和 |
avg | 平均值 |
max | 最大值 |
min | 最小值 |
分组函数使用时,必须先进行分组(通过where或者其它语句筛选过后),才能使用。
若没有对数据进行分组,则整张表作为一个分组。
在分组函数后面使用where进行条件筛选的话,效率会变低
分组函数不能直接使用在where子句中
例子:
找出比最低工资高的员工信息
select ename as '姓名' ,sal as '薪资' from emp where sal > min(sal);
结果:
ERROR 1111 (HY000): Invalid use of group function :分组函数的使用无效
invalid:无效的 (valid:有效的)
所有的分组函数可以组合在一起使用
select sum(sal) as '工资总和',max(sal) as '最高工资',min(sal) as '最低工资',avg(sal) as '平均工资',count(*) as '数据总数' from emp;
结果:
+----------+----------+----------+-------------+----------+
| 工资总和 | 最高工资 | 最低工资 | 平均工资 | 数据总数 |
+----------+----------+----------+-------------+----------+
| 29025.00 | 5000.00 | 800.00 | 2073.214286 | 14 |
+----------+----------+----------+-------------+----------+
在comm中,有数据为null的话,分组函数会自动忽略null
例如,数据为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HtYJ3xE6-1690357313916)(MySQL.assets/image-20220730192707185.png)]
当我们使用sum函数进行累加时:
因为其中有null,所以正常的运算符进行计算的话,则会返回null(因为null参加了运算,详情见上一章单行处理函数。
但是使用分组函数时,函数会自动忽略其中的null,不需要提前对null进行处理。
select sum(comm) as '补助总和' from emp;
结果:
+----------+
| 补助总和 |
+----------+
| 2200.00 |
+----------+
1 row in set (0.00 sec)
统计出符合条件的记录数
select count(ename) as 'emp表内的总数据数' from emp;
注意:count不会统计null的数量,会自动忽略null
select count(comm) as '补助总数' from emp;
结果为:
+----------+
| 补助总数 |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
count(*) 和 count(具体字段)的区别:
count(*):查询所有的记录的数量,只要一条记录中有一个字段不为空,这条记录就是有效的,统计所有有效的字段。
count(具体字段):表示统计该字段下所有不为null的记录数量,当其中有为null的数据时,会跳过该记录。
找出数据中最大的一项。
例子:
找出最高工资?
select max(sal) as '最高工资' from emp;
找出数据中最小的一项
select min(sal) as '最低工资' from emp;
取出所有数据的平均值
select avg(sal) as '平均工资' from emp;
在实际的应用中,可能需要对所有数据中的某一部分数据进行操作,这时候我们就要需要使用分组查询。
select ....
from ...
group by ...
举例:计算每个部门的工资和?
计算每个岗位的平均薪资?
计算某个部门的最高薪资?
select ...
from ...
where ...
group by...
order by ...
以上是书写顺序
执行顺序:
1.from ...
2.where ...
3.group by ...
4.select ...
5.order by ...
select ename,sal from emp where sal > min(sal);
结果:
ERROR 1111 (HY000): Invalid use of group function
分组函数的无效使用
注意,此时的where在group by之前执行,也就是说,在分组之前会执行条件筛选,如此一来,按照正常逻辑写的数据查询,可能会出错,得到错误的结果。
为什么分组函数不能直接使用在where后面?
因为分组函数在使用的时候必须先进行分组,where执行的时候还没有分组,所以where后面不能出现分组函数。
select sum(sal) from emp;
这个没有分组,为啥sum()函数可以用呢?
因为 select 在 group by 之后执行 (按照如上的执行顺序) 。
having 是在group by分组之后,进一步对分组的数据进行筛选的关键字,不能脱离order by 单独使用,一定是紧跟在group by 后面的。
思路:按照岗位分组,然后对每个分组进行求和
所以 group by job 然后会用到 sum() 函数
select job as '工作',sum(sal) as '岗位薪资'
from emp
group by job;
分析:
执行顺序:从emp中查询数据,根据job字段进行分组,然后对每个分组执行sum()求和
思考:可以将ename加入select的条件吗?
可以,但是结果不符合需求或者输出错误的值
select ename,job,sum(sal) from emp group by job;
以上语句在mysql中可以执行,但是毫无意义,
以上语句在oracle中执行,会产生错误。
(说明mysql中的sql语法相对于oracle来说更加的松散)
结论:
在一条select查询语句当中,若其中有group by语句,select 后面只能跟 参加分组的字段,以及分组的函数。
思路:先按照每个部门的部门编号进行分组,然后使用max()分组函数进行取值。
select deptno as '部门编号', max(sal) as '部门最高薪资' from emp group by deptno;
结果为:
+----------+--------------+
| 部门编号 | 部门最高薪资 |
+----------+--------------+
| 20 | 3000.00 |
| 30 | 2850.00 |
| 10 | 5000.00 |
+----------+--------------+
3 rows in set (0.00 sec)
思路:先按照每个部门进行分组,然后按照工作进行分组,最后使用max()
按照多个字段进行分组,不同字段之间用逗号隔开
select deptno as '部门编号',job as '工作',max(sal) as '最高工资' from emp group by deptno,job order by deptno;
结果:
+----------+-----------+----------+
| 部门编号 | 工作 | 最高工资 |
+----------+-----------+----------+
| 10 | CLERK | 1300.00 |
| 10 | MANAGER | 2450.00 |
| 10 | PRESIDENT | 5000.00 |
| 20 | ANALYST | 3000.00 |
| 20 | CLERK | 1100.00 |
| 20 | MANAGER | 2975.00 |
| 30 | CLERK | 950.00 |
| 30 | MANAGER | 2850.00 |
| 30 | SALESMAN | 1600.00 |
+----------+-----------+----------+
9 rows in set (0.00 sec)
思路:先按照每个部门进行分组,然后使用max函数显示最高的工资,然后通过having进行对分组后的数据进一步筛选。
select deptno as '部门编号',max(sal) as '最高工资' from emp group by deptno having max(sal)>3000;
执行结果:
+----------+----------+
| 部门编号 | 最高工资 |
+----------+----------+
| 10 | 5000.00 |
+----------+----------+
1 row in set (0.00 sec)
思考:以上的SQL语句的执行效率是否过低?
比较低,实际可以先将大于3000的数据找出来之后再进行分组。
参考:https://blog.csdn.net/weixin_34377065/article/details/94023858
select
deptno as '部门编号',max(sal) as '最高工资'
from
emp
where
sal>3000
group by
deptno;
优化策略:where和having 优先选择 where,where完成不了的,再选择having
思路:按照每个部门进行分组,然后用avg()函数取平均值,然后筛选出2500以下的。
select deptno as '部门编号',round(avg(sal),1) as '最高工资' from emp group by deptno having avg(sal)>2500;
单表查询章节结束
select ....
from ...
where ...
group by ...
having ...
order by ...
执行顺序:
1.from
2.where
3.group by
4.having
5.select
6.order by
案例:
找出每个岗位的平均薪资,要求显示平均薪资大于1500的,除去工作岗位为Manager的,且按照平均薪资进行降序排序。
思路:按照每个岗位进行分组,然后使用having去进行第二次平均薪资的筛选,然后使用not in manager 除去工作岗位为manager的,然后使用order by 平均薪资 desc 进行排序。
select
job as '工作岗位',round(avg(sal),1) as '平均工资'
from
emp
where
job not in ('manager') // job != 'manager'也可以
group by
job
having
avg(sal)>1500
order by
avg(sal) desc;
+-----------+----------+
| 工作岗位 | 平均工资 |
+-----------+----------+
| PRESIDENT | 5000 |
| ANALYST | 3000 |
+-----------+----------+
2 rows in set (0.00 sec)
从一张表中单独查询称为单表查询
多张表的数据,从A表中取出一部分,从B表中去除一部分,将这两部分连接起来,查询,称为连接查询。
年份进行分类
SQL92:1992年出现的语法
SQL99:1999年出现的语法
连接方式分类
内连接
等值连接
非等值连接
自连接
外连接
左外连接(左连接
右外连接(右连接
全连接
案例:查询每个员工所在部门的名称?
select ename,deptno from emp;
select denptno,dname from dept;
select emp.ename as '员工姓名',emp.deptno as '部门编号',dept.dname as '部门名称'
from emp,dept; //没有任何条件限制
+----------+----------+------------+
| 员工姓名 | 部门编号 | 部门名称 |
+----------+----------+------------+
| SMITH | 20 | OPERATIONS |
| SMITH | 20 | SALES |
| SMITH | 20 | RESEARCH |
| SMITH | 20 | ACCOUNTING |
| ALLEN | 30 | OPERATIONS |
| ALLEN | 30 | SALES |
| ALLEN | 30 | RESEARCH |
| ALLEN | 30 | ACCOUNTING |
...
| MILLER | 10 | OPERATIONS |
| MILLER | 10 | SALES |
| MILLER | 10 | RESEARCH |
| MILLER | 10 | ACCOUNTING |
+----------+----------+------------+
56 rows in set (0.00 sec)//共有56条 笛卡尔积现象
当两张表进行连接查询,没有任何限制的时候,最终的结果是两张表记录的乘积,A表有5条,B表有6条,则结果就又5*6=30条。
这个现象叫做笛卡尔积现象。
得出结论:在进行表连接时,需要在连接时将条件增加到后面:
select emp.ename as '员工姓名',emp.deptno as '部门编号',dept.dname as '部门名称'
from emp,dept
where dept.deptno=emp.deptno;//指定相同字段
结果:
+----------+----------+------------+
| 员工姓名 | 部门编号 | 部门名称 |
+----------+----------+------------+
| 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 |
+----------+----------+------------+
14 rows in set (0.00 sec)
最终的查询结果条数是14条,但是在匹配的过程中,匹配的次数还是没有减少,依然是56次,但是4选1。
就算加上条件也无法避免底层的匹配次数,底层还是会把表中的每一条行数据都给匹配一遍,只是显示的结果是有效数据
降低表的连接次数也是性能优化的重要手段
select e.ename as '员工姓名',e.deptno as '部门编号',d.dname as '部门名称'
from emp as e,dept as d
where e.deptno=d.deptno;//指定相同字段 SQL92语法
给表名起别名的话,使用as的话,好像会报错(未验证过
为什么select上可以直接使用from 的时候才定义的表别名呢?
因为执行顺序的不同(见上一章),首先执行的是from,后执行的select。
使用表名前缀可以提高执行效率。
如果使用了表的别名,则不能再使用表的真名。
性能影响可以忽略不计,但是您可以更好地阅读查询。这只是为了你的方便。
性能影响是在SQL Server程序本身中分配几kb的内存来存储别名等。与执行查询所需的其余操作相比,这几乎是小菜一碟。
例:
查询每个员工所在的部门名称,并显示员工名称和部门名称
#SQL92语法
select
e.ename as '员工名',d.dname as '部门名'
from
emp e,dept d
where
e.deptno=d.deptno;
#92语法:结构不清晰,where后面容易混杂
#SQL99语法
select
e.ename as '员工名',d.dname as '部门名'
from
emp e
inner join
dept d
on
e.deptno=d.deptno <-连接条件
where
e.ename='smith';
#inner 可以省略 表示内连接,inner 可读性更好
#表连接和筛选语法进行了分离
#99语法后 on后面依然可以添加where来进行筛选
例子:
找出每个员工的薪资等级,要求显示员工名,薪资和薪资等级。
select
e.ename as '员工名称',e.sal as '工资',s.grade as '工资等级'
from
emp e
inner join
salgrade s
on
e.sal between s.losal and hisal
order by
e.sal asc;
例子:
查询员工的上级领导,要求显示员工名和对应的领导名称
select
e.empno as '员工编号',e.ename as '员工名',e.mgr as '领导编号',b.ename as '领导名称'
from
emp e
inner join
emp b
on
ifnull(e.mgr,7839) = b.empno;
#ifnull替换空值为king的员工编号(自己是自己的领导),否则查询出来只有12条记录
结果:
+----------+--------+----------+----------+
| 员工编号 | 员工名 | 领导编号 | 领导名称 |
+----------+--------+----------+----------+
| 7369 | SMITH | 7902 | FORD |
| 7499 | ALLEN | 7698 | BLAKE |
| 7521 | WARD | 7698 | BLAKE |
| 7566 | JONES | 7839 | KING |
| 7654 | MARTIN | 7698 | BLAKE |
| 7698 | BLAKE | 7839 | KING |
| 7782 | CLARK | 7839 | KING |
| 7788 | SCOTT | 7566 | JONES |
| 7839 | KING | NULL | KING |
| 7844 | TURNER | 7698 | BLAKE |
| 7876 | ADAMS | 7788 | SCOTT |
| 7900 | JAMES | 7698 | BLAKE |
| 7902 | FORD | 7566 | JONES |
| 7934 | MILLER | 7782 | CLARK |
+----------+--------+----------+----------+
14 rows in set (0.00 sec)
外连接的例子:
#内连接的特点:必须完全匹配的数据才能被查出来
select
e.ename as '员工名',d.dname as '部门名'
from
emp e
inner join
dept d
on
e.deptno=d.deptno;
#外连接:把匹配不上的数据也依然显示出来
select
e.ename as '员工名',d.dname as '部门名'
from
emp e
right join
dept d
on
e.deptno=d.deptno;
#外连接中,两张表是有主次关系的,需要指定主表,主表中的数据将会完全显示出来。
#内连接中两张表没有主次关系。
#任何一个左连接都有一个右连接的写法
#任何一个右连接都有一个左连接的写法
#外连接的查询结果条数 一定 大于等于 内连接的查询结果条数
#outer关键字可以省略
#外连接:把匹配不上的数据也依然显示出来
#主要是为了将这张表的所有数据全都查询出来,捎带着关联查询左边的表
#就是为了将符合两个表条件的数据 和 右边表剩余的,没有匹配上的数据的全部显示出来
select
e.ename as '员工名',d.dname as '部门名'
from
emp e
right outer join
dept d
on
e.deptno=d.deptno;
select
e.ename as '员工名',d.dname as '部门名'
from
emp e
left outer join
dept d
on
e.deptno=d.deptno;
案例:
查询每个员工的上级领导,要求显示所有员工的名字和领导名
select
a.ename as '员工名称',b.ename as '领导名称'
from
emp a
left outer 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 |<= king也被显示出来了
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+----------+----------+
14 rows in set (0.00 sec)
全连接显示两侧表中所有满足检索条件的行。
只做一个了解,实际需求用的很少
了解一下写法就行了
#oracle 的全连接
select * from a full join b on a.id = b.id
#mysql 的全连接
select * from a left join b on a.id = b.id
union
select * from a right join b on a.id = b.id
#若我们想要连接3、4、5张表怎么办?
select ...xxx
from ...a
(inner)join ...b
on ...a.x=b.y
left (outer) join ...c
on ...b.x=c.y
right (outer) join ...d
on ...c.x=d.y
group by ...
where ...
order by ...
#以此类推
案例:
找出每个员工的部门名称以及工资等级和上级领导,且要显示员工名、部门名、领导名、薪资、薪资等级
#各个表结构(只展示一部分):
mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
mysql> select * from emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
思路:三个表连接,然后显示对应的字段即可。
select
e.ename as '员工名称',d.dname as '部门名称',e2.ename as '领导名称',e.sal as '薪资',s.grade as '薪资等级'
from
emp e
inner join
dept d
on
e.deptno=d.deptno
inner join
salgrade s
on
e.sal between s.losal and s.hisal
left outer join
emp e2
on
e.mgr=e2.empno;
结果为:
+----------+------------+----------+---------+----------+
| 员工名称 | 部门名称 | 领导名称 | 薪资 | 薪资等级 |
+----------+------------+----------+---------+----------+
| SMITH | RESEARCH | FORD | 800.00 | 1 |
| ALLEN | SALES | BLAKE | 1600.00 | 3 |
| WARD | SALES | BLAKE | 1250.00 | 2 |
| JONES | RESEARCH | KING | 2975.00 | 4 |
| MARTIN | SALES | BLAKE | 1250.00 | 2 |
| BLAKE | SALES | KING | 2850.00 | 4 |
| CLARK | ACCOUNTING | KING | 2450.00 | 4 |
| SCOTT | RESEARCH | JONES | 3000.00 | 4 |
| KING | ACCOUNTING | NULL | 5000.00 | 5 | <=左外连接显示了领导编号为null的
| TURNER | SALES | BLAKE | 1500.00 | 3 |
| ADAMS | RESEARCH | SCOTT | 1100.00 | 1 |
| JAMES | SALES | BLAKE | 950.00 | 1 |
| FORD | RESEARCH | JONES | 3000.00 | 4 |
| MILLER | ACCOUNTING | CLARK | 1300.00 | 2 |
+----------+------------+----------+---------+----------+
14 rows in set (0.00 sec)
select 中嵌套 select 查询语句,被嵌套的 select 语句称为子查询。
select
..(select)
from
..(select)
where
..(select)
#综上,select可以出现在select\from\where语句的后面
案例:找出比最低工资高的员工姓名和工资
select ename,sal
from emp
where sal > (select min(sal) from emp);
#程序会首先执行子查询 select min(sal) from emp; 得到最低的工资
#然后就根据查询到的最低工资与sal对比,然后返回所有满足条件的记录
from后面的子查询,可以将子查询的查询结果当做一张临时表(技巧)
案例:
找出每个岗位的平均工资的工资等级(按照岗位分组,求平均值,再进行分等级)
#首先按照岗位来分组,算出平均工资
select job,round(avg(sal),0) from emp group by job;
#然后算出来的表如下:
+-----------+-------------------+
| job | round(avg(sal),0) |
+-----------+-------------------+
| CLERK | 1038 |
| SALESMAN | 1400 |
| MANAGER | 2758 |
| ANALYST | 3000 |
| PRESIDENT | 5000 |
+-----------+-------------------+
5 rows in set (0.00 sec)
#然后把这个表跟salgrade进行连接
select
temp.job as '工作岗位',temp.avgsal as '岗位平均工资',s.grade as '薪资等级'
from
(select job,round(avg(sal),0) as avgsal from emp group by job) temp
inner join
salgrade s
on
temp.avgsal between s.losal and s.hisal;
一定要有嵌套的思想,和明确的思路,每个表查出来是什么要有一个大概的认识。
找出每个员工的部门名称,要求显示员工名和部门名
select e.ename,d.dname,d.dname
from emp e
join dept d
on e.deptno=d.deptno
order by e.ename;
#select 子句 有且只能有返回一条数据
select e.ename as '员工名',(select d.dname from dept d where e.deptno=d.deptno) as '部门名称' from emp e order by e.ename;
select子查询在select之后时,子查询只能每次查询返回一条结果。
“UNION表示“并”,当用的时候,系统会自动将重复的元组去掉,如果要保留重复元组则就用UNION ALL UNION 会合并重复数据,(由于要合并重复,该操所 隐藏着一个 排序的操作.)UNION ALL 简单合并,不会合并重复的. SQL中union运算操作的理解 在SQL中,对于并运算,可以使用union关键字.”
#union 的效率会高一些 对于表连接来说
#每连接一次表,匹配次数满足笛卡尔积
#但是union可以减少匹配的次数,在减少匹配次数的情况下,可以完成两个结果集的合并、拼接
# a表连接b表
# a、b、c三个表各有10条数据,则连接需要(笛卡尔积)10*10*10=1000次
# 使用union连接三个表:a连接b:10*10=100 a连接c:10*10=100 总需:100+100=200次
# 1000>200次
select ename,job from emp where job="manager"
union
select ename,job from emp where job="salesman"
select ename,job from emp where job="manager"
union
select ename from emp where job="salesman"
==>
ERROR 1222 (21000): The used SELECT statements have a different number of columns
#以上语句是错误的,因为union在合并结果集的时候,要求两个查询的结果必须列数相同
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 |
+--------+---------+
7 rows in set (0.01 sec)
#以上语句在mysql中可以执行,但是在oracle中会报错,因为oracle语法更加严格。
limit 是将查询结果集的一部分显示出来,通常使用在分页查询之中。
分页是为了提高用户的体验。
limit 跟在语句最后面
limit 有两个参数,一个是其实的下标,第二个是要取的长度
当limit 后面只跟一个参数时,默认是将要取的长度。
注意:起始下标从0开始,且在mysql中,limit在order by之后执行
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 |
+-------+---------+
5 rows in set (0.00 sec)
#在mysql中,limit在order by之后执行
在mysql中,limit在order by之后执行
# limit的起始位置跟数组的起始位置是一样的
如:
arr[]={1,2,3,4,5,6,7,8,9}
limit 5,2 取出的将会是{6,7}
下标默认是从0开始的
limit 0,2 取出的是 {1,2}
limit 1,2 取出的是 {2,3}
案例:
取出工资排名是在【5-9】名的员工
#
select ename as '员工名称',sal as '工资'
from emp
order by sal desc
limit 4,5;
#第一个参数是从第5名开始的,由于下标是从0开始,所以第一个参数是5-1=4
#注意:是第5到9名员工,实际上是 [5,6,7,8,9] 结果中是包含了5的
#所以第二个参数是 (9-5)+1=5条记录
#需求:需要我们每页显示3条数据
#先确定第二条数据,第二条数据是页面大小,也就是返回的数据条数,所以是3 固定不变
第一页: limit 0,3 [0,1,2]
第二页: limit 3,3 [3,4,5]
第三页: limit 6,3 [6,7,8]
第四页: limit 9,3 [9,10,11]
....
指定页面大小为pageSize
指定当前页码为pageNum
那么可以得出
第pageNum页: limit pageSize(pageNum-1),pageSize*
//模拟后台管理的分页
@Controller
public static void main(String[] args){
int pageNo=5;
int pageSize=10;
int startIndex = (pageN0 -1 ) * pageSize;
String sql="select ename from emp order by ename desc limit"+startIndex+','+pageSize+";"
//...然后使用SQL
}
select
...
from
...
where
...
group by
...
having
...
order by
...
limit
...