目录
前言:
1,Create
1.1,单行数据+全列插入
1.2,单行数据+指定列插入
1.3,多行数据+全列插入
1.4,多行数据+指定列插入
1.5,插入否则更新
1.6,替换
2,Retrieve (读取)
2.1,全列查询
2.2,指定列查询
2.3,查询字段为表达式
2.4,为查询结果指定别名
2.5,结果去重
2.6,where条件
2.7,结果排序
2.8,筛选分页结果
3,Update
4,Delete
4.1,删除数据
4.2,删除整张表
4.3,截断表
5, 插入查询结果
6,聚合函数
7,group by子句的使用
结语:
前言:
本篇主要讲述对于表内容的增删查改及相关查询语句:CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除)
1,Create
语法:
insert into 表名 (指定列) values (values1,values2,...)
示例:
- 创建一张学生表
mysql> create table students(
-> id int unsigned primary key auto_increment,
-> sn int not null unique comment '学号',
-> name varchar(20) not null,
-> qq varchar(20) unique);
1.1,单行数据+全列插入
- 插入数据
注意在这里插入的时候也可以不指明id,因为我们定义了auto_increment属性,mysql会使用默认的值自增。
mysql> insert into students values (1,101,'张三',1111);
mysql> insert into students values (2,102,'李四',11222);
- 查看插入结果
select * from students;
1.2,单行数据+指定列插入
- 指定列插入数据
mysql> insert into students (sn,name,qq) values (103,'李四',11333);
mysql> insert into students (id,sn,name) values (10,104,'王五');
1.3,多行数据+全列插入
mysql> insert into students values (20,105,'赵六',2222) ,(21,106,'田七',3333);
1.4,多行数据+指定列插入
mysql> insert into students (sn,name) values (116,'北京'),(117,'上海');
1.5,插入否则更新
在插入数据的时候,由于主键和唯一键的存在,可能导致插入的数据已经存在而插入失败。
如果需要更新,可以进行更新操作。也就是在插入数据时,如果不存在就直接插入,如果存在,发生冲突了,就将原来的数据更新为插入的数据。这个和STL中的unordered_map类似,在使用[ ]的时候,如果存在就更新,如果不存在就插入。
语法:
insert ...... on duplicate key update column=value[......]
示例:
mysql> insert into students values (1,101,'张三',55555) on duplicate key update id=1,sn=101,name='张三',qq=55555;
在更新的时候也要保证不和其他值冲突。
1.6,替换
替换replace与上面的插入更新类似,如果数据存在就替换,如果数据不存在就直接插入。
mysql> replace into students (sn,name) values (120,'广州');//不存在直接插入
mysql> replace into students (id,sn,name,qq) values (1,101,'苏州',99999);//数据已经存在,则替换掉原数据
2,Retrieve (读取)
首先创建一张学生成绩表,作为示例
mysql> create table exam_result(
-> id int unsigned primary key auto_increment,
-> name varchar(20),
-> chinese int,
-> math int,
-> english int);
向表中插入一些数据:
mysql> insert into exam_result (name,chinese,math,english) values ('孙悟空',87,78,77);
mysql> insert into exam_result (name,chinese,math,english) values ('猪悟能',88,98,90);
mysql> insert into exam_result (name,chinese,math,english) values ('曹孟德',82,84,67);
mysql> insert into exam_result (name,chinese,math,english) values ('刘玄德',55,85,45);
mysql> insert into exam_result (name,chinese,math,english) values ('孙权',70,73,78);
mysql> insert into exam_result (name,chinese,math,english) values ('宋公明',75,65,30);
2.1,全列查询
mysql> select * from exam_result;
通常情况 下不建议使用 * 进行全列查询
- 查询的列越多意味着需要传输的数据量越大;
- 可能会影响到索引的作用。(索引在后面更新)
2.2,指定列查询
select 筛选的列名称 from 表名
示例:
mysql> select id,name,math from exam_result;
mysql> select id,name,chinese from exam_result;
2.3,查询字段为表达式
- 表达式不包含字段
mysql> select id,name,math,10 from exam_result;
mysql> select id,name,math,10+10 from exam_result;
- 表达式中包含一个字段
mysql> select id,name,math+10 from exam_result;
- 表达式中包含多个字段
mysql> select id,name,math+chinese+english from exam_result;
2.4,为查询结果指定别名
select column [as] 别名 from 表名;
示例:
mysql> select id,name,math+chinese+english as total from exam_result;
mysql> select id,name,math+chinese+english '总分' from exam_result;
2.5,结果去重
math列中的数据98重复了。
去重,需要使用distinct
mysql> select distinct math from exam_result;
2.6,where条件
前面讲的select 用法,是用来筛选出哪些列,而接下来的这部分内容where条件,是筛选出满足条件的行。
比较运算符
- >,>=,<,<=:大于,大于等于,小于,小于等于
- =:等于,比较null值时不安全,比如null=null返回的结果是null
- <=>:等于,比较null值时是安全的,比如null=null返回的结果是1
- !=,<>:不等于
- between a0 and a1:范围匹配,[a0,a1],如果a0<=values<=a1,返回true(1)
- in(option...):如果是option中的任意一个,返回true(1)
- is null:是空
- is not null:不是空
- like:模糊匹配。%表示任意多个字符(包括0个),_表示任意一个字符
逻辑运算符
- and:多个条件必须都为true,结果才为true
- or:只要有一个条件为true,结果就为true
- not:如果条件为true(1),结果就为false(0)
null和null的比较,=和<=>的比较:
使用案例:
- 英语成绩不及格的同学及英语成绩(<60)
mysql> select name,english from exam_result where english<60;
- 语文成绩在[80,90]的同学及语文成绩
mysql> select name,chinese from exam_result where chinese>=80 and chinese<=90;
mysql> select name,chinese from exam_result where chinese between 80 and 90;
- 数学成绩是58或者59或者98或者99的同学及数学成绩
mysql> select name,math from exam_result where math=58 or math=59 or math=98 or math=99;
mysql> select name,math from exam_result where math in (58,59,98,99);
- 姓孙的同学
mysql> select name from exam_result where name like '孙%';
- 孙某同学
mysql> select name from exam_result where name like '孙_';
- 语文成绩好于英语成绩的同学
//where条件中比较运算符两侧都是字段
mysql> select name,chinese,english from exam_result where chinese>english;
- 总分在200分以下的同学
mysql> select name,math+chinese+english from exam_result where math+chinese+english<200;
前面在select内容部分,我们可以为查询结果math+chinese+english取别名。但在where子句中是否可以使用别名呢?
可以看到是不能使用的。这和mysql的执行顺序有关。
总结:先确定操作哪张表,再根据where子句的条件筛选出我们想要的数据,最后再显示出来。
所以在where子句中不能使用别名,但在select中仍然可以使用。
- 语文成绩>80并且不姓孙的同学
mysql> select name,chinese from exam_result where chinese>80 and name not like '孙%';
- 孙某同学,或者总成绩>200并且语文成绩<数学成绩并且英语成绩>80
mysql> select name,chinese,math,english,chinese+math+english '总分' from exam_result where name like '孙_' or (chinese+math+english>200 and chinese<math and english>80);
2.7,结果排序
语法:
---ASC 升序(从小到大)
---DESC 降序(从大到小)
---默认为ASC
select ...... from table_name [where...] order by column [ASC|DESC];
注意:null视为比任何值都小
案例:
- 查询同学及数学成绩,数学成绩按照升序显示
mysql> select name,math from exam_result order by math;
- 查询同学各门成绩,依次按数学降序,英语升序,语文升序的方式显示
mysql> select name,math,english,chinese from exam_result order by math desc,english,chinese;
- 查询同学及总分, 由高到低
mysql> select name,math+chinese+english from exam_result order by chinese+math+english desc;
order by 子句可以使用别名
mysql> select name,math+chinese+english '总分' from exam_result order by 总分 desc;
在这里为什么可以使用别名了呢?同样这和mysql的子句执行顺序有关。
总结:首先我们需要确定操作哪张表,如果第二步就执行排序,其实表中有一部分数据是不需要进行排序的, 这样做太浪费时间和空间了。所以先确定操作哪张表,再根据where子句条件筛选出来我们要的数据,这时的数据一定是被筛选出来的有价值的数据,这时我们只是选出来数据了,不给显示出来,最后经过排序,再将数据显示出来。
因此执行ordere by时,别名已经定义了,所以可以使用。
2.8,筛选分页结果
语法:
----起始下标从0开始
---从0开始,筛选n条结果
select ......from table_name [where...] [order by...] limit n;
---从s开始,筛选n条结果
select ......from table_name [where...] [order by...] limit s,n;
---从s开始,筛选n条结果,和第二种方法表示一样
select ......from table_name [where...] [order by...] limit n offset s;
注意:limit的执行顺序比order by还要靠后
按id进行分页,分别显示第1,2,3页
3,Update
语法:
update table_name set column=expr [column=expr...] [where...] [order by...] [limit...]
案例:
- 将孙悟空同学的数学成绩变更为80
mysql> update exam_result set math=80 where name='孙悟空';
- 将曹孟德同学的数学成绩变更为60,语文成绩变更为70
mysql> update exam_result set math=60,chinese=70 where name='曹孟德';
- 将总成绩倒数前 3的同学的数学成绩加上30分
mysql> select name,math,chinese+math+english 总分 from exam_result order by 总分 limit 3;
4,Delete
4.1,删除数据
语法:
delete from table_name [where...] [order by...] [limit ...]
注意:如果delete from 表名,会将表的内容清空
案例:
- 删除孙悟空同学的考试成绩
mysql> delete from exam_result where name='孙悟空';
4.2,删除整张表
- 准备测试表
mysql> create table for_delete(
-> id int primary key auto_increment,
-> name varchar(20));其中id有自增属性。
- 插入测试数据
mysql> insert into for_delete values (1,'A'),(2,'B'),(3,'C');
- 查看测试数据
- 删除整张表 ,查看删除结果
mysql> delete from for_delete;
mysql> select * from for_delete;
- 删除表之前id自增到3,现在插入一条新数据。
mysql> insert into for_delete (name) values ('D');
可以发现在清空表后,id的自增值没有变为0。可以通过show查看表结构。
mysql> show create table for_delete\G
4.3,截断表
语法:
truncate [table] table_name
注意:这个 操作慎用
1,这个操作只能对整张表使用,不能向delete一样针对部分数据操作
2,不对数据操作,所以比delete快,但是truncate 在删除数据的时候,并不经过正真的事务,所以无法回滚
3,该操作与delete相比,它会重置auto_increment项
案例:
- 准备测试表(和for_delete表属性一样)
mysql> create table for_truncate like for_delete;
- 插入测试数据 ,查看测试数据
mysql> insert into for_truncate values (1,'A'),(2,'B'),(3,'C');
mysql> select * from for_truncate;
- 截断整表数据,注意影响行数是0,所以实际上没有对表真正操作
mysql> truncate table for_truncate;
- 查看删除结果
mysql> select * from for_truncate;
- 再插入 一条数据,自增id重新开始增长
mysql> insert into for_truncate (name) values ('D');
- 查看表结构
mysql> show create table for_truncate \G
5, 插入查询结果
语法:
insert into table_name [column...] select ...
案例:删除表中的重复记录,重复数据只能有一份
- 创建原数据表
mysql> create table duplicate_table(
-> id int,
-> name varchar(20));
- 插入测试数据
mysql> insert into duplicate_table values (100,'aaa'), (100,'aaa'), (200,'bbb'), (200,'bbb'), (200,'bbb'), (300,'ccc');
思路:
- 创建一张空表no_duplicate_table,结构和duplicate_table一样
mysql> create table no_duplicate_table like duplicate_table;
- 将 duplicate_table数据去重插入到no_duolicate_table表中
mysql> insert into no_duplicate_table select distinct * from duplicate_table;
- 通过重命名,做到原子的去重操作
mysql> rename table duplicate_table to old_duplicate_table;
mysql> rename table no_duplicate_table to duplicate_table;
- 查看最终结果
6,聚合函数
count():返回查询到的数据的数量
sum():返回查询到的数据的总和,不是数字没有意义
avg():返回查询到的数据的平均值,不是数字没有意义
max():返回查询到的数据的最大值,不是数字没有意义
min():返回查询到的数据的最小值,不是数字没有意义
案例:
- 统计班级共有多少学生
//使用*做统计
mysql> select count(*) from exam_result;
//使用表达式统计
mysql> select count(1) from exam_result;
- 统计数学成绩总分
mysql> select sum(math) from exam_result;
- 统计平均总分
mysql> select avg(chinese+math+english) 平均总分 from exam_result;
- 统计数学成绩中不重复的成绩个数
mysql> select count(distinct math) 不重复的个数 from exam_result;
- 返回英语最高分
mysql> select max(english) from exam_result;
- 返回>70分以上的最低分
mysql> select min(math) from exam_result where math>70;
7,group by子句的使用
在select 中使用group by子句可以对指定列进行分组查询。
select column1 column2... from table group by column
案例:
准备工作,创建一个雇员信息数据库:
- emp员工表
- dept部门表
- salgrade工作等级表
- 如何显示每个部门的平均工资和最高工资
mysql> select deptno,avg(sal),max(sal) from emp group by deptno;
总结:
分组,可以理解为把一张表按照条件在逻辑上分成了很多子表,然后分别对各自的子表进行聚合统计。
分组聚合结果:
- 显示每个部门的每种岗位的 平均工资和最低工资
mysql> select job,deptno,avg(sal),min(sal) from emp group by job,deptno;
- 显示平均工资低于2000的部门和它的平均工资
首先统计各个部门的平均工资
mysql> select deptno,avg(sal) from emp group by deptno;
having和group by配合使用,对group by的结果进行过滤
mysql> select deptno,avg(sal) 平均工资 from emp group by deptno having 平均工资<2000;
having经常和group by搭配使用,作用是对分组进行筛选,作用有些像where
结语:
最后在这里再加曾经的一道面试题:
SQL查询中各个关键字的执行顺序:from>on>join>where>group by>with>having>select>distinct>order by>limit
下篇博主会再更新一些相关的实战OJ题