文章目录
- mysql基本查询通关手册:从crud到分组统计,新手避坑全攻略
-
- 一、先搞懂:表是什么?
- 二、create:先建一张表
-
- 2.1 最简单的建表例子
- 2.2 大白话解释每个词
- 2.3 新手建表避坑
- 三、insert:往表里加数据
-
- 3.1 单行全列插入
- 3.2 指定列插入
- 3.3 一次插多行
- 3.4 插入避坑
- 四、select:从表里查数据
-
- 4.1 查所有列
- 4.2 只查指定列
- 4.3 给列起个别名
- 4.4 按条件筛选:where
-
- 常用比较运算符
- 逻辑运算符
- 模糊查询:like
- ⚠️ 超级大坑:null不能用=判断
- 4.5 新手高频报错:where里用别名
- 4.6 排序:order by
- 4.7 分页:limit
- 五、update:修改表里的数据
-
- 5.1 修改指定行
- 5.2 ❗️ 致命提醒:千万别忘写where
- 5.3 更新避坑
- 六、delete:删除表里的数据
-
- 6.1 删除指定行
- 6.2 ❗️ 致命提醒:千万别忘写where
- 6.3 清空全表的另一种方式:truncate
- 6.4 delete和truncate的区别
- 七、分组统计:聚合函数 + group by
-
- 7.1 五个常用聚合函数
- 7.2 group by到底在干嘛?
- 7.3 基本用法:分组 + 聚合
-
- 例1:统计每个班有多少人
- 例2:统计每个班的数学成绩情况
- 例3:多字段分组
- 7.4 新手灵魂拷问:分完组,原始行还在吗?
- 7.5 想要明细 + 分组统计?用窗口函数
- 7.6 having:分组后筛选
- 7.7 where和having的区别
- 八、必懂底层逻辑:sql执行顺序
-
- 8.1 真实执行顺序
- 8.2 大白话类比:做菜的顺序
- 8.3 懂了执行顺序有啥用?
- 九、新手避坑终极清单
- 十、最后:ai时代怎么学
mysql基本查询通关手册:从crud到分组统计,新手避坑全攻略
很多刚接触mysql的同学,一听到“数据库”“sql”就觉得很高深。其实完全不用怕,你就把数据库表当成一张班级花名册,所有操作全是日常逻辑:
- 画一张新的空白表格 = 建表(create)
- 往表格里填新同学信息 = 插入数据(insert)
- 从表格里找人、找成绩 = 查询数据(select)
- 修改表格里写错的信息 = 更新数据(update)
- 把同学从表格里划掉 = 删除数据(delete)
这四个操作合起来就是数据库里最基础的crud。今天咱们完全从零起步,用大白话+可直接运行的例子,把mysql基本语法讲明白,新手也能看完就上手敲。
一、先搞懂:表是什么?
表,就是一张有行有列的表格,和excel里的表一模一样:
- 列(字段):表格的表头,比如姓名、学号、语文成绩,规定了这一列能填什么类型的数据
- 行(记录):表格里的每一行数据,比如一个同学的所有信息就是一行记录
后面所有操作,我们都用「学生成绩表」当例子,跟着敲一遍就能学会。
二、create:先建一张表
说白了就是画一张空白表格,先定好有几列、每列叫什么、能填啥。
2.1 最简单的建表例子
我们先建一张学生表:
create table students (
id int unsigned primary key auto_increment comment '编号',
sn int not null unique comment '学号',
name varchar(20) not null comment '姓名',
qq varchar(20) comment 'qq号'
);
2.2 大白话解释每个词
不用死记,知道大概意思就行:
| int | 整数类型,这一列只能填整数,比如学号、编号 |
| varchar(20) | 字符串类型,能填文字,括号里是最大长度,比如姓名最多20个字 |
| not null | 这一列不能为空,必须填值,比如姓名肯定不能空着 |
| primary key | 主键,相当于这一行的身份证号,唯一不重复,一般都用id当主键 |
| auto_increment | 自动递增,id不用自己填,数据库会自动按1、2、3…帮你排号 |
| unique | 唯一约束,这一列的值不能重复,比如学号肯定不能两个人一样 |
| comment 'xxx' | 备注,相当于给列写注释,方便以后看懂 |
2.3 新手建表避坑
三、insert:往表里加数据
建完空表,就该往里面填数据了,就像往花名册里登新同学信息。
3.1 单行全列插入
给每一列都按顺序填值,值的数量和顺序必须和建表时完全对应:
insert into students values (100, 10000, '唐三藏', null);
小提示:id设置了自动递增,其实可以不用写。如果不指定id,mysql会自动帮你生成递增的编号。
3.2 指定列插入
只想填某几列,其他列留空或者用默认值,就指定列名再插:
— 只填id、学号、姓名,qq号不填
insert into students (id, sn, name) values (101, 10001, '孙悟空');
这是开发里最常用的写法,灵活不容易错。
3.3 一次插多行
一条一条插太慢,一条语句可以插多条数据,中间用逗号隔开:
insert into students (id, sn, name) values
(102, 20001, '曹孟德'),
(103, 20002, '孙仲谋');
3.4 插入避坑
四、select:从表里查数据
查询是日常用得最多的操作,没有之一。说白了就是从表格里找出你想要的信息。
为了方便演示查询,我们再建一张成绩表并插入测试数据:
— 建成绩表
create table exam_result (
id int unsigned primary key auto_increment,
name varchar(20) not null comment '同学姓名',
class varchar(10) comment '班级',
chinese float default 0.0 comment '语文成绩',
math float default 0.0 comment '数学成绩',
english float default 0.0 comment '英语成绩'
);
— 插入7条测试数据
insert into exam_result (name, class, chinese, math, english) values
('唐三藏', '一班', 67, 98, 56),
('孙悟空', '一班', 87, 78, 77),
('猪悟能', '一班', 88, 98, 90),
('曹孟德', '二班', 82, 84, 67),
('刘玄德', '二班', 55, 85, 45),
('孙权', '三班', 70, 73, 78),
('宋公明', '三班', 75, 65, 30);
4.1 查所有列
select * from exam_result;
*代表所有列,执行后会把整张表的所有行所有列都查出来。
❌ **新手注意:正式工作里别写select ***
4.2 只查指定列
想查什么列就写什么列,列的顺序可以随便换:
— 只查姓名和英语成绩
select name, english from exam_result;
4.3 给列起个别名
列名太长或者是计算出来的,可以给它起个好懂的外号,用as或者直接空格加名字:
— 计算三科总分,起个别名叫总分
select name, chinese + math + english as 总分 from exam_result;
— 省略as,直接空格加别名,效果一样
select name, chinese + math + english 总分 from exam_result;
4.4 按条件筛选:where
这是查询的灵魂。说白了就是只找出符合条件的行,比如“找出英语不及格的同学”。
常用比较运算符
每个都配一个小例子,看完就会用:
| > >= < <= | 大于、大于等于、小于、小于等于 | select name, english from exam_result where english < 60; 查英语不及格的 |
| = | 等于 | select name from exam_result where math = 98; 查数学刚好98分的 |
| != | 不等于 | select name from exam_result where math != 98; 查数学不是98分的 |
| between a and b | 在a和b之间,包含a和b | select name, chinese from exam_result where chinese between 80 and 90; 查语文80-90分的 |
| in (a,b,c) | 是其中任意一个 | select name, math from exam_result where math in (98, 78); 查数学是98或者78分的 |
| is null | 是空的 | select name from students where qq is null; 查没填qq号的同学 |
| is not null | 不是空的 | select name from students where qq is not null; 查填了qq号的同学 |
逻辑运算符
多个条件组合的时候用:
| and | 并且,两个条件都要满足 | select name from exam_result where chinese > 80 and math > 80; 语文数学都大于80 |
| or | 或者,满足一个就行 | select name from exam_result where chinese > 90 or math > 90; 语文或数学有一门大于90 |
| not | 不满足 | select name from exam_result where not math = 98; 数学不是98分的 |
⚠️ 新手必踩坑:and优先级比or高 多个条件混写的时候,一定要用括号明确优先级。
错误写法(本意:语文>80,并且姓孙或姓曹):
select * from exam_result where chinese > 80 and name like '孙%' or name like '曹%';
实际会变成:「语文>80且姓孙」或者「所有姓曹的」,范围完全错了。
正确写法:
select * from exam_result where chinese > 80 and (name like '孙%' or name like '曹%');
模糊查询:like
只记得名字里的某个字,就用模糊查询:
- %:匹配任意多个字(包括0个)
- _:匹配严格的一个字
— 找所有姓孙的同学,孙后面有多少字都行
select name from exam_result where name like '孙%';
— 找名字是两个字、姓孙的同学,孙后面只能有一个字
select name from exam_result where name like '孙_';
⚠️ 超级大坑:null不能用=判断
这是90%的新手第一次都会写错的。
mysql里的null是「不知道、不确定」的意思,不是0,也不是空字符串。
错误写法,永远查不到结果:
select name, qq from students where qq = null;
正确写法:
select name, qq from students where qq is null;
新手记住:判断是不是null,固定用is null或者is not null,别用等号。
4.5 新手高频报错:where里用别名
这也是入门必踩的坑,先看错误写法:
select name, chinese+math+english total
from exam_result
where total < 200;
报错:unknown column 'total' in 'where clause'
大白话原因:mysql执行的时候,先执行where筛选,后执行select计算别名。等where筛选的时候,total这个外号还没起好,所以不认。
三种正确写法:
— 写法1:把表达式原样写一遍,推荐这么写,性能最好
select name, chinese+math+english total
from exam_result
where chinese+math+english < 200;
— 写法2:用having代替where,简单查询可以凑合用
select name, chinese+math+english total
from exam_result
having total < 200;
— 写法3:用子查询包一层,复杂查询通用
select name, total
from (
select name, chinese+math+english total
from exam_result
) t
where total < 200;
4.6 排序:order by
查出来的数据太乱?按指定列排个序。
- asc:升序,从小到大,默认就是这个
- desc:降序,从大到小
— 按数学成绩从低到高排
select name, math from exam_result order by math;
— 按总分从高到低排,可以用别名
select name, chinese + math + english 总分 from exam_result order by 总分 desc;
也可以按多列排序,先按前面的排,前面相同再按后面的排:
— 先按数学降序,数学分数一样的话,再按英语升序
select name, math, english from exam_result
order by math desc, english asc;
4.7 分页:limit
数据太多一次看不完,一页一页看。
两种常用写法:
— 直接取前3条
select id, name from exam_result limit 3;
— 从第0条开始,取3条(第1页)
select id, name from exam_result limit 3 offset 0;
— 从第3条开始,取3条(第2页)
select id, name from exam_result limit 3 offset 3;
新手注意:offset是从0开始数的,不是从1开始。 好习惯:查不熟悉的表,先加个limit 1试试,防止表太大把数据库查卡死。
五、update:修改表里的数据
说白了就是修改表格里已有的内容,比如同学成绩登错了要改。
5.1 修改指定行
比如把孙悟空的数学成绩改成80分:
update exam_result set math = 80 where name = '孙悟空';
一次改多列也可以:
update exam_result set math = 60, chinese = 70 where name = '曹孟德';
也可以在原来的基础上改,比如给倒数三名的数学加30分:
update exam_result set math = math + 30
order by chinese + math + english limit 3;
注意:mysql不支持math += 30这种简写,必须写math = math + 30。
5.2 ❗️ 致命提醒:千万别忘写where
— 这行会把全表所有人的语文成绩都改成0!
update exam_result set chinese = 0;
这是数据库最经典的事故,没有之一。忘写where就会更新全表,数据毁了很难恢复。
安全小技巧: 改数据前,先把where条件复制到select里查一遍,确认是你要改的那些行,再执行update。
5.3 更新避坑
六、delete:删除表里的数据
就是删掉表格里的行,比如同学退学了从花名册里移除。
6.1 删除指定行
比如删掉孙悟空的成绩:
delete from exam_result where name = '孙悟空';
6.2 ❗️ 致命提醒:千万别忘写where
和update一样,不加where会删掉全表所有数据:
— 清空整张表,非常危险
delete from exam_result;
6.3 清空全表的另一种方式:truncate
想快速清空整张表,用truncate比delete快得多:
truncate table exam_result;
6.4 delete和truncate的区别
大白话总结一下:
| 能不能删部分行 | 能,加where就行 | 不能,只能清空全表 |
| 删错了能不能恢复 | 能,事务里可以回滚 | 不能,删了就没了 |
| 速度 | 慢,逐行删,大表特别慢 | 极快,直接扔掉整张表再新建 |
| 自增id | 不重置,接着原来的号继续 | 重置,从1重新开始 |
总结:删部分数据用delete;确定要清空全表、不需要恢复,用truncate。
七、分组统计:聚合函数 + group by
光查单行数据不够,我们经常要做统计,比如“每个班的平均分”“每个班有多少人”,这就用到group by分组统计了。
7.1 五个常用聚合函数
说白了就是把一堆数据算成一个结果,比如求和、求平均。
| count(*) | 统计一共有多少行 | select count(*) from exam_result; 统计班级总人数 |
| sum(列) | 求和,把这一列所有数加起来 | select sum(math) from exam_result; 算数学成绩总分 |
| avg(列) | 求平均值 | select avg(english) from exam_result; 算英语平均分 |
| max(列) | 求最大值 | select max(chinese) from exam_result; 找语文最高分 |
| min(列) | 求最小值 | select min(math) from exam_result; 找数学最低分 |
7.2 group by到底在干嘛?
你可以把group by理解成给数据打包装袋、按堆分类。
没分组的时候,你面对的是一行一行的学生,可以查某个人的成绩。 执行group by class之后,数据会按班级打包成一个个独立的小组:
- 一班一袋,里面装着一班所有同学的记录
- 二班一袋,里面装着二班所有同学的记录
- 三班一袋,里面装着三班所有同学的记录
核心变化:分组之后,你面对的最小单位,从「单个学生」变成了「整个班级」。 你不能再直接问“这个组里学生叫什么名字”,因为一个组里有好多学生;你只能问“这个班有多少人”“这个班平均分多少”这种针对整个组的问题。
7.3 基本用法:分组 + 聚合
分组必须和聚合函数搭配用。聚合函数就是专门用来「把一组数据算成一个数」的,刚好对应分组后的组级计算。
例1:统计每个班有多少人
select class, count(*) as 人数
from exam_result
group by class;
运行结果:
+——–+——–+
| class | 人数 |
+——–+——–+
| 一班 | 3 |
| 二班 | 2 |
| 三班 | 2 |
+——–+——–+
例2:统计每个班的数学成绩情况
select
class,
avg(math) as 数学平均分,
max(math) as 数学最高分,
min(math) as 数学最低分
from exam_result
group by class;
运行结果:
+——–+————–+————–+————–+
| class | 数学平均分 | 数学最高分 | 数学最低分 |
+——–+————–+————–+————–+
| 一班 | 91.333 | 98 | 78 |
| 二班 | 84.500 | 85 | 84 |
| 三班 | 69.000 | 73 | 65 |
+——–+————–+————–+————–+
例3:多字段分组
group by后面可以跟多个字段,就是按多个维度层层细分。 比如按班级+性别分组(假设有gender字段):
select class, gender, count(*)
from exam_result
group by class, gender;
就是先按班级分,每个班里再按性别分,统计每个班每个性别的人数。
7.4 新手灵魂拷问:分完组,原始行还在吗?
磁盘上的原表:完完整整还在,一点没动。 group by只是读取数据做计算,属于查询操作,不会修改、删除原表里的任何数据。
这条查询返回的结果里:原始明细被压缩了,看不到组内每一行。 就像打包之后,你只能看到袋子外面写的“总重量、总个数”,看不到袋子里每一个水果。
这也是新手最常见报错的根源:
— 错误写法,mysql 5.7+默认直接报错
select class, name from exam_result group by class;
原因:分组后每个班有好几个name,数据库不知道该返回哪一个,所以直接拒绝。 旧版本关闭严格模式后会随机返回一个name,结果不可控,业务里绝对不能用。
7.5 想要明细 + 分组统计?用窗口函数
如果既想保留所有原始学生明细,又想看到每个班的平均分,group by做不到,要用窗口函数partition by。
简单对比:
- group by class:压缩分组,每组只输出1行统计结果,原始明细不在结果里
- partition by class:不压缩分组,所有原始行全部保留,每一行都附带本组的统计值
示例(了解即可,属于进阶内容):
select
class, name, math,
avg(math) over(partition by class) as 班级平均分
from exam_result;
输出效果:
+——–+——–+——+————+
| class | name | math | 班级平均分 |
+——–+——–+——+————+
| 一班 | 唐三藏 | 98 | 91.33 |
| 一班 | 孙悟空 | 78 | 91.33 |
| 一班 | 猪悟能 | 98 | 91.33 |
| 二班 | 曹孟德 | 84 | 84.50 |
| 二班 | 刘玄德 | 85 | 84.50 |
| 三班 | 孙权 | 73 | 69.00 |
| 三班 | 宋公明 | 65 | 69.00 |
+——–+——–+——+————+
7.6 having:分组后筛选
分组完了,想把不符合条件的整个组去掉,用having。
比如找出数学平均分大于80的班级:
select class, avg(math) as 数学平均分
from exam_result
group by class
having avg(math) > 80;
7.7 where和having的区别
面试常考,也是新手最容易混的,一句话讲明白: where是分组前筛行,having是分组后筛组。
打个比方:
- 公司招员工,先看学历筛掉一批人(where,筛个体)
- 剩下的人按部门分组,算每个部门的平均工资
- 再把平均工资太高的部门整个砍掉(having,筛整个组)
| 什么时候执行 | 分组之前 | 分组之后 |
| 筛什么 | 一行一行的数据 | 分好的整个组 |
| 能用聚合函数吗 | 不能 | 能 |
| 性能 | 好,先过滤数据少 | 差一点 |
最佳实践:能在where里过滤的,就别放到having里,性能更好。
八、必懂底层逻辑:sql执行顺序
很多新手疑惑:为什么where里不能用别名?为什么having里能用聚合函数?
答案很简单:sql写的顺序,和实际执行的顺序,完全不一样。
8.1 真实执行顺序
from → where → group by → having → select → distinct → order by → limit
8.2 大白话类比:做菜的顺序
不用死记,就按做菜的逻辑想:
顺着这个逻辑想,很多问题自然就懂了:
- 为什么where不能用别名?择菜的时候,菜还没装盘呢,哪来的菜名
- 为什么order by能用别名?都摆完盘了,当然知道菜名
- 为什么where不能用聚合函数?菜都没分类,怎么算每堆的平均重量
8.3 懂了执行顺序有啥用?
九、新手避坑终极清单
十、最后:ai时代怎么学
现在ai写sql又快又准,很多人说不用学sql了。其实不是不用学,是不用死背语法了,但底层逻辑必须懂。
- 基础的写法、函数名,忘了可以查,甚至让ai直接写
- 但执行顺序、null逻辑、分组原理、性能逻辑这些东西,必须理解。这是你判断ai写得对不对、排查线上问题的底气。
把ai当校对工具,不是答案工具。自己先写,再和ai的结果对比,想清楚为什么不一样,进步才最快。
mysql基本查询是后端开发的基本功,看似简单,细节和坑非常多。但只要你顺着数据流动的逻辑去理解,不用死记也能牢牢掌握。多敲多练,很快就能熟练。
网硕互联帮助中心



评论前必须登录!
注册