MySQL基本查询
- 表的增删查改
- Create(增)
- Retrieve(查)
- select列
- 全列查询
- 指定列查询
- 查询字段为表达式
- 为查询结果指定别名
- 结果去重
- where 条件
- 英语不及格的同学的英语成绩
- 语文成绩在 [80, 90] 分的同学及语文成绩
- 数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
- 姓孙的同学
- 孙某同学
- 语文成绩好于英语成绩的同学
- 总分在 200 分以下的同学
- 语文成绩 > 80 并且不姓孙的同学
- 孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
- 结果排序
- 同学及数学成绩,按数学成绩升序显示
- 同学及 qq 号,按 qq 号排序显示
- 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
- 查询同学及总分,由高到低
- 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
- 筛选分页结果
- 按 id 降序进行分页,每页 3 条记录,分别显示 第 1、2、3 页
- update(改)
- 将孙悟空同学的数学成绩变更为 80 分
- 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
- 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
- 将所有同学的语文成绩更新为原来的 2 倍
- delete(删)
- 删除孙悟空同学的考试成绩
- 删除整张表数据
- 截断表
- 插入查询结果
- 删除表中的的重复复记录,重复的数据只能有一份
- 聚合函数
- 什么是聚合函数?
- MySQL常见聚合函数
- 统计班级共有多少同学
- 统计班级收集的 qq 号有多少
- 统计本次考试的数学成绩分数个数
- 统计本次考试去重过后的数学成绩分数个数
- 统计数学成绩总分
- 统计平均总分
- 返回英语最高分
- 返回 > 70 分以上的数学最低分
- group by子句的使用
- 测试案例
- 显示每个部门的平均工资和最高工资
- 显示每个部门的每种岗位的平均工资和最低工资
- 显示平均工资低于2000的部门和它的平均工资
表的增删查改
CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除)
Create(增)
语法:
insert into tablename [(colname1,colname2…)] values(num1,num2,…);
eg:
先创建一个表,然后再向表里面插入数据:
然后向里面插入数据(正常插入:)
上面的插入方式,是按照指定列的方式来进行插入的,我们在插入的时候,可以不用指定要插入那些列的名字,而直接插入值,这时候这种插入方式叫做 ‘全列插入’:
当然我们也可以指定某些列的插入顺序,比如我就是要先插入年龄,在插入姓名、学号、性别,可以吗?当然可以:
对于可以缺省的,我们在插入的时候也可以不显示指定进行插入,比如本例中id是可以缺省的、性别、年龄也是可以缺省的,那么我们在插入的时候就可以不显示指定性别、id、年龄进行插入:
如果我们想一次性插入多行数据可以吗?
当然可以:
多行插入:
如果还想要插入更多行数据,直接添加多行数据即可:
一般情况下,我们插入主键或唯一键重复的数据时,数据会告诉我们键值冲突,为此我们会插入失败:
但是我们就是要插入values(‘司马光’,9,‘男’,90)这行数据怎么办?
我们可以利用语法:
insert ..... on duplicate key update colname1=xxx,colname2=yyy.....
on duplicate key:如果发生键值冲突
这句话的意思就是:如果当前插入的数据发生键值冲突,那么就将发生键值冲突行的数据更新为后面的数据:
比如上例中我们就是要插入:values(‘司马光’,9,‘男’,90)这行数据1,MySQL语句就可以这样写:
insert into students values('司马光',9,'男',90) on duplicate key update name='司马光',age=90,sex='男';
效果如图:
替换:
如果发生键值冲突,那么就将冲突行数据替换成后续的数据;
如果没有发生键值冲突,那么就不发生替换,直接进行插入;
语法:
replace into tablename (colname1,colname2,...) values(x1,x2,...)
eg:
Retrieve(查)
select列
语法:
SELECT [DISTINCT] {* | {column [, column] ...} [FROM table_name] [WHERE ...] [ORDER BY column [ASC | DESC], ...] LIMIT ...
eg:
创建表结构:
然后向里面插入一些数据:
全列查询
如果我们要查询所有列的属性的话,我们可以按照以下方式:
select colnam1,colname2,..... from tablename;
对应本例中就是:
select id,name,chinese,math,english from exam_result;
但是这样查询所有列的话比较麻烦,要写出所有列的名称,为了简单,我们可以利用 ‘*’ 这个通配符来表示所有列,为此我们查询所有列的语句就可以变为:
select * from tablename;
eg:
但是在实际使用使用中,我们不建议直接使用全列查询,因为实际的数据库可能很大,我们使用全列查询的话,很可能导致我们的电脑刷屏,观察数据也不太清楚,其次,如果我们使用全列查询的话,就意味着我们需要使用更多的网络资源来进行传输数据;
指定列查询
指定列查询,顾名思义就是查询指定列的数据,没有显示指定查询的就不会显示:
eg:
指定列的数据不一定按照定义表的顺序来;
查询字段为表达式
- 表达式不包含任何列字段:
对于不包含任何列字段的表达式,在最后打印的时候会新增一列然后原样输出;- 表达式包含一个列字段:
数据库会自动将表达式计算过后再输出;
(对于上述SQL语句的理解:读取id字段、name字段、语文成绩+10字段从exam_result表中)- 表达式中包含多个列字段:
(对于上述SQL语句的理解:读取id字段、name字段、三科总和字段从exam_result表中);
为查询结果指定别名
语法:
select colname1 [as] newcolname1,colname2 [as] newcolname2... from tablename
eg:
结果去重
语法:
select distinct colname from tablename;
eg:
where 条件
在MySQL中where就相当于C/C++语言中的if语句;
比较运算符:
运算符 | 说明 |
---|---|
>,>=,<,<= | 大于,大于等于,小于,小于等于 |
= | 等于(注意不是赋值),null不安全,也就是说=不能参与null的比较,比如:null=null的结果是null,1=null的结果也是null,而不是布尔值 |
<=> | 等于,null是安全的也就是说<=>可以参与null的比较,比如:null<=>null,结果是1;1<=>null,结果是0;也就是说如果参与等于运算的数据中可能含有null,我们建议用<=>来比较; |
!=,<> | 这两个不等于符号对于null来说都是不安全的,!=,<>都不能参与null的比较,比如:null!=null or null<>null 结果都是null;1!=null or 1<> null 结果都是null; |
between a0 and a1 | 范围匹配,[a0,a1],如果a0<=value<=a1,则返回true(1) |
in(option…) | value是option中的任意一个返回true(1) |
is null | value 是null?是,返回true(1) |
is not null | value 不是是null吗?不是,返回true(1) |
like | 模糊匹配.%表示任意多个字符(包括0个),_表示任意一个字符 |
逻辑运算符:
运算符 | 说明 |
---|---|
and | 逻辑与 |
or | 逻辑或 |
not | 逻辑取反 |
英语不及格的同学的英语成绩
分析:
需要读取的列:
姓名、英语成绩;
帅选条件:英语成绩<60;
SQL语句:
select name,english from exam_result where english < 60;
语文成绩在 [80, 90] 分的同学及语文成绩
分析:
需要读取的列:
姓名、语文成绩;
筛选条件: chinese大于等于80并且小于等于90;
SQL语句:
select name ,chinese from exam_result where chinese>=80 and chinese<= 90;
SQL语句还可以这样写:
select name,chinese from exam_result where chinese between 80 and 90;
数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
分析:
需要读取的列:
姓名、数学成绩;
筛选条件:数学成绩是 58 或者 59 或者 98 或者 99 分;
SQL语句:
select name,math from exam_result where math=58 or math=59 or math=98 or math=99;
SQL语句还可以这样写:
select name,math from exam_result where math in(58,59,98,99);
姓孙的同学
分析:
需要读取的列:
姓名
筛选条件:姓孙的同学;
SQL语句:
select name from exam_result where name like '孙%';
孙某同学
分析:
需要读取的列:
姓名
筛选条件:孙某
SQL语句:
select name from exam_result where name like '孙_';
语文成绩好于英语成绩的同学
分析:
需要读取的列:
姓名、语文成绩、数学成绩;
筛选条件:语文成绩大于英语成绩
SQL语句:
select name,chinese,english from exam_result where chinese>english;
总分在 200 分以下的同学
分析:
需要读取的列:
姓名、总分
筛选条件:总分<200
SQL语句:
select name,english+chinese+math from exam_result where english+chinese+math<200;
注意:
这里不能向以下这样写:
select name,english+chinese+math as 总分 from exam_result where 总分<200;
这样写是会报错的,报错原因是因为数据库不认识 ‘总分’ 这个字符,为什么呢?我们不是已经在前面已经将english+chinese+math重命名为 ‘总分’ 了嘛?按理来说 ‘总分’ 这个标识就等价于 english+chinese+math 啊,为什么还会报错?这就与MySQL执行的顺序先后相关了,在MySQL中是先执行读取操作操作在执行筛选操作?还是先执行筛选操作再执行读取操作?
很明显是先执行的筛选操作,MySQL在第一次遍历的时候就带着筛选条件来进行遍历的,这一次遍历就能拿到最后的结果!而如果我们是先遍历,再在遍历结果过中进行筛选的话,那么就会进行两次遍历,很明显存在浪费!因此MySQL选择那种方式就显而易见了,既然是先使用的筛选条件,可是筛选条件为 ‘总分’ < 200 这个’总分’并不存在于数据库列中啊,自然就报未知列名错误!我们这是属于先使用后重命名,数据库不认识是很正常的!
语文成绩 > 80 并且不姓孙的同学
分析:
需要读取的列:
姓名、语文成绩
筛选条件:语文成绩大于80并且不姓孙;
SQL语句:
select name,chinese from exam_result where chinese > 80 and (not (name like '孙%'));
孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
分析:
需要读取的列:
姓名、语文成绩、数学成绩、英语成绩、总成绩;
筛选条件: 孙某同学 或者 总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
SQL语句:
select name,chinese,math,english ,math+chinese+english from exam_result where name like '孙_' or (math+chinese+english >200 and chinese <math and english >80);
结果排序
语法:
ASC:升序
DESC:降序
默认升序
select ... from tablename [where] order by colname [ASC|DESC];
注意:没有order by的语句返回的结果是未定义的,永远不要依赖,尽管它看起来有序!
测试表结构:
测试表中数据:
同学及数学成绩,按数学成绩升序显示
分析:
需要读取列:
姓名、数学成绩
筛选条件:无
排序:以数学成绩排升序
SQL语句:
select name,math from exam_from order by math ASC;
同学及 qq 号,按 qq 号排序显示
分析:
需要读取的列:
姓名、qq;
筛选条件:无;
排序:以qq号为升序或者降序;
SQL升序语句:
select name,qq from exam_result order by qq ASC;
我们可以发现null值比任何值都小,因此被排在最上面!
SQL降序语句:
select name,qq from exam_result order by qq DESC;
我们可以发现,null比任何值都要小,因此被排在最小面;
查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
分析:
需读取的列:
姓名、数学成绩、英语成绩、语文成绩
筛选条件:无
排序:依次按 数学降序,英语升序,语文升序
SQL语句:
select name,math,english,chinese from exam_result order by math DESC ,english ASC,chinese ASC;
这个的应用场景就是:
首先按照数学成绩排序数学成绩高的排前面,数学成绩相等,则看英语成绩,英语成绩小的排前面,如果英语成绩还想等,则看语文成绩,语文成绩小的排前面,如果语文成绩还想等,看程序员自己的控制!
查询同学及总分,由高到低
分析:
需读取的列:
姓名、总分
筛选条件:无
排序:按总分降序
SQL语句:
select name,english+math+chinese as 总分 from exam_result order by 总分 DESC;
注意:这里的话是先执行的读取,然后在进行的排序,也就是说重命名工作先进行,再进行的排序,因此在进行排序工作的时候数据库认识 ‘总分’ 就是 english+math+chinese 因此才没有报出未知列的错误!
查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
分析:
需读取的列:
姓名、数学成绩
筛选条件:姓孙或者姓曹
排序:按数学成绩降序排序
SQL语句:
select name,math from exam_result where name like '孙%' or name like '曹%' order by math DESC;
筛选分页结果
语法:
起始下标为0;
select ...from tablename [where...] [order by...] limit n;
//从0开始读取n条记录;
select ...from tablename [where...] [order by...] limit s,n;
//从s开始读取n条记录;
select ...from tablename [where...] [order by...] limit n offset s;
//从s开始读取n条记录;
建议:对未知表进行查询时,最好加一条 LIMIT 1,避免因为表中数据过大,查询全表数据导致数据库卡死;
按 id 降序进行分页,每页 3 条记录,分别显示 第 1、2、3 页
分析:
需要读取的列:
全列;
筛选条件:无
排序:id降序;
每页显示:3条
SQL语句:
第一页:
select * from exam_result order by id DESC limit 0,3;
第二页:
select * from exam_result order by id DESC limit 3,3
;
第三页:
select * from exam_result order by id DESC limit 6,3;
update(改)
语法:
UPDATE table_name SET column = expr [, column = expr ...] [WHERE ...] [ORDER BY ...] [LIMIT ...]
使用案例:
将孙悟空同学的数学成绩变更为 80 分
分析:
更新列: 数学成绩;
更新条件: 孙悟空
SQL语句:
update exam_result set math=80 where name='孙悟空';
如果想要完成以上的效果的话,使用以下SQL也是可以的:
insert into exam_result values(2,'孙悟空',87,80,77,null) on duplicate key update math=80;
将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
分析:
更新列: 数学、语文;
更新条件: 曹孟德
SQL语句:
update exam_result set math=60,chinese=70 where name ='曹孟德';
将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
分析:
更新列: 数学
更新条件: 总成绩倒数前3
SQL语句:
update exam_result set matn=math+30 order by english +math +chinese ASC limiit 0,3;
将所有同学的语文成绩更新为原来的 2 倍
分析;
更新列: 语文条件
更新条件: 无
SQL语句:
update exam_result set chinese =chinese*2;
delete(删)
语法:
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
测试案例:
删除孙悟空同学的考试成绩
分析:
删除列: 所有列
删除条件: 孙悟空
SQL语句:
delete from exam_result where name='孙悟空';
删除整张表数据
删除列: 所有列
删除条件: 无
SQL语句:
delete from exam_result;
这个语句比较危险,为了后面能够更好的做案例,我们使用一些测试用例来尝试:
在使用delete删除表中所有数据过后,auto_increment的值不会重置:
截断表
语法:
TRUNCATE [TABLE] table_name
这个语句与delete from tablename;
效果类似都是删除表中的所有数据,但是这个删除与与delete删除语句有点不同:
- 只能对整表操作,不能对部分数据进行操作,delete可以;
- truncate实际上不对数据操作,所以比 DELETE 更快,但是TRUNCATE在删除数据的时候,并不经过真正的事物,所以无法回滚;
- 会重置 AUTO_INCREMENT 项
eg:
插入查询结果
语法:
INSERT INTO table_name [(column [, column ...])] SELECT ...;
删除表中的的重复复记录,重复的数据只能有一份
分析:
聚合函数
什么是聚合函数?
聚合函数:就是MySQL专门针对一组数据进行统计的内置函数;
MySQL常见聚合函数
聚合函数 | 功能 |
---|---|
count([distinct]) expr | 返回某列的行数 |
sum([distinct] expr) | 返回某列的总和,遇到NULL会忽略,不是数字没有意义 |
avg([distinct] expr) | 返回某一列的平均值,不是数字没有意义 |
max([distinct] expr ) | 返回某一列的最大值,不是数字没有意义 |
min([distinct] expr) | 返回某一列的最小值,不是数字没有意义 |
测试表数据:
统计班级共有多少同学
SQL语句:
select count(*) from exam_result;
使用表达式做统计:
统计班级收集的 qq 号有多少
SQL语句:
select count(qq) from exam_result;
当count具体统计某一列数据时,如果这一列数据为null时,则不会被统计!
统计本次考试的数学成绩分数个数
SQL语句:
select count(math) from exam_result;
统计本次考试去重过后的数学成绩分数个数
SQL语句:
select count(distinct math) from exam_result;
统计数学成绩总分
SQL语句:
select sum(math) from exam_result;
统计平均总分
SQL语句:
select sum(english+math+chinese ) /count(*) from exam_result;
或者也可以使用avg聚合函数:
SQL语句:
select avg(english+chinese+math) from exam_result;
返回英语最高分
SQL语句:
select max(english) from exam_result;
返回 > 70 分以上的数学最低分
SQL语句:
select min(math) from exam_result where math>70;
group by子句的使用
在select语句中使用group by 子句可以对指定列进行分组查询;
语法:
select .... from tablename [where] group by colname1,colname2...
测试案例
准备工作,创建一个雇员信息表(来自oracle 9i的经典测试表)
emp员工表
dept部门表
salgrade工资等级表
DROP database IF EXISTS `scott`;
CREATE database IF NOT EXISTS `scott` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;USE `scott`;DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (`deptno` int(2) unsigned zerofill NOT NULL COMMENT '部门编号',`dname` varchar(14) DEFAULT NULL COMMENT '部门名称',`loc` varchar(13) DEFAULT NULL COMMENT '部门所在地点'
);DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (`empno` int(6) unsigned zerofill NOT NULL COMMENT '雇员编号',`ename` varchar(10) DEFAULT NULL COMMENT '雇员姓名',`job` varchar(9) DEFAULT NULL COMMENT '雇员职位',`mgr` int(4) unsigned zerofill DEFAULT NULL COMMENT '雇员领导编号',`hiredate` datetime DEFAULT NULL COMMENT '雇佣时间',`sal` decimal(7,2) DEFAULT NULL COMMENT '工资月薪',`comm` decimal(7,2) DEFAULT NULL COMMENT '奖金',`deptno` int(2) unsigned zerofill DEFAULT NULL COMMENT '部门编号'
);DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade` (`grade` int(11) DEFAULT NULL COMMENT '等级',`losal` int(11) DEFAULT NULL COMMENT '此等级最低工资',`hisal` int(11) DEFAULT NULL COMMENT '此等级最高工资'
);insert into dept (deptno, dname, loc)
values (10, 'ACCOUNTING', 'NEW YORK');
insert into dept (deptno, dname, loc)
values (20, 'RESEARCH', 'DALLAS');
insert into dept (deptno, dname, loc)
values (30, 'SALES', 'CHICAGO');
insert into dept (deptno, dname, loc)
values (40, 'OPERATIONS', 'BOSTON');insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, null, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, null, 10);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19', 3000, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7839, 'KING', 'PRESIDENT', null, '1981-11-17', 5000, null, 10);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7844, 'TURNER', 'SALESMAN', 7698,'1981-09-08', 1500, 0, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7876, 'ADAMS', 'CLERK', 7788, '1987-05-23', 1100, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, null, 30);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, null, 20);insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, null, 10);insert into salgrade (grade, losal, hisal) values (1, 700, 1200);
insert into salgrade (grade, losal, hisal) values (2, 1201, 1400);
insert into salgrade (grade, losal, hisal) values (3, 1401, 2000);
insert into salgrade (grade, losal, hisal) values (4, 2001, 3000);
insert into salgrade (grade, losal, hisal) values (5, 3001, 9999);
emp员工表
dept部门表
salgrade工资等级表
显示每个部门的平均工资和最高工资
分析:
select avg(sal),max(sal) from emp group by deptno;
如果我们想知道是哪个部分的平均工资和最高工资,我们在读取的时候可以读取工作名;
SQL语句:
select deptno ,avg(sal),max(sal) from emp group by deptno;
显示每个部门的每种岗位的平均工资和最低工资
SQL语句:
select deptno,job ,avg(sal),min(sal) from emp group by deptno,job;
显示平均工资低于2000的部门和它的平均工资
分析:
1、先读取每个部门的平均工资:
SQL语句:
select deptno ,avg(sal) from emp group by deptno;
2、然后从上表的结果中筛选出平均工资低于2000的数据;
SQL语句:
select deptno ,avg(sal) as 平均工资 from emp group by deptno having 平均工资<2000;
这里我们用到了having子句,having 子句与where子句一样都是起筛选作用的,但是二者却有所不同:
- 首先是在SQL中的执行顺序不同,where 的筛选条件先执行,having的筛选条件后执行;
- 两者的语义也是有所不同where的筛选主要用于分组查询之前进行筛选将筛选结果组成一组,而having的筛选主要用于分组查询之后,对查询结果在进行筛选;
这里我们举个例子:
我们可以来查询一下,将SCOTT与KING这两个人排除在外的 平均工资低于2000的部门和它的平均工资:
1、SCOTT与KING排除在外的每个部门的平均工资:
SQL语句:
select deptno,avg(sal) as 平均工资 from emp where ename!='SCOTT' and ename!='KING' group by deptno;
2、基于上面这个分组查询的结果,我们利用having筛选出符合条件的数据:
select deptno,avg(sal) as 平均工资 from emp where ename!='SCOTT' and ename!='KING' group by deptno having 平均工资<2000;
我们来解析以下上面的SQL语句的执行顺序:
面试题:SQL查询中各个关键字的执行先后顺序 from > on> join > where > group by > with > having > select> distinct > order by > limit