1 ~> 数据插入(Create)
先从最基础的插入操作说起,INSERT语句的核心职责就是向数据表中添加新行。你可以选择只为部分列赋值,也可以一次性完成全列插入,甚至能够通过一条语句批量插入多行数据。值得注意的是,在MySQL中,INTO这个关键字是可以省略的,虽然这并非标准SQL的写法,但实际使用起来确实非常便捷。

1.1 基础 INSERT 插入
单行指定列插入
-- 只为部分列赋值,其余列会自动采用默认值或NULL INSERT INTO students (id, sn, name) VALUES (10, 124, '关羽');
单行全列插入
-- 必须严格按照表定义时的列顺序,将每个字段的值依次传入 INSERT INTO students VALUES (1, 123, '张飞', '4567890');
多行批量插入
-- 一次提交多行数据,相比逐行插入,执行效率显著提升 INSERT INTO students (id, sn, name, qq) VALUES (13, 127, '许攸', '10423456'), (14, 128, '许褚', '12333445'), (15, 129, '诸葛亮', '3213456');
1.2 插入否则更新(ON DUPLICATE KEY UPDATE)
当你准备插入的数据与表中已有的主键或唯一键发生冲突时,不必急于处理报错,ON DUPLICATE KEY UPDATE能够将这个冲突自动转化为更新操作。具体来说,返回的行数有特定含义:正常插入返回1,发生更新返回2,如果更新后的值与原来一致,则返回0。
-- 假如id=18这条记录已经存在,那就更新它的sn、name、qq字段 INSERT INTO students (id, sn, name, qq) VALUES (18, 134, '貂蝉', '1112222') ON DUPLICATE KEY UPDATE sn = 134, name = '貂蝉', qq = '11133333'; -- 查看上一次DML操作影响了多少行 SELECT row_count();
1.3 REPLACE 替换插入
REPLACE INTO的执行逻辑相对直接:它会先尝试插入,如果没有冲突,正常插入(影响1行);如果发生冲突,它会先将旧行删除,再插入新行(影响2行,自增ID会跳一个)。
需要特别留意的是,REPLACE包含删除操作,这会触发删除触发器,并可能影响外键的级联行为。因此,不要将它和ON DUPLICATE KEY UPDATE混为一谈,两者的机制完全不同。
-- sn是唯一键,如果140已经存在,那就先删后插 REPLACE INTO students (sn, name, qq) VALUES (140, '许攸', '321456213');
2 ~> SELECT 检索基础
2.1 基础查询形式
查询数据时,全列查询可以直接使用*将整张表的数据全部拉取出来,但在生产环境中强烈不建议这样做——数据量较大时,传输速度会变慢,还可能导致索引失效。更推荐的做法是,明确列出你所需要的字段。
-- 全列查询(不推荐) SELECT * FROM exam_result; -- 指定列查询,性能更优,可读性也更强 SELECT id, name, math FROM exam_result;
2.2 表达式查询与别名
SELECT后面不仅可以接字段,还能接常量、运算表达式,甚至函数。为列起别名可以使用AS,也可以直接省略。
-- 计算三科总分,并给这个计算结果起个别名叫total SELECT name, math, chinese + math + english AS total FROM exam_result; -- 省略AS的写法,更加简洁 SELECT name 姓名, math 数学, chinese + math + english 总分 FROM exam_result;
2.3 结果去重
使用DISTINCT可以去除查询结果中重复的行。如果查询多列,它会按照多列的组合值来进行去重。
-- 只看数学成绩有哪些不同的分数 SELECT DISTINCT math FROM exam_result;
3 ~> WHERE 条件筛选
3.1 比较运算符
| 运算符 | 说明 | 注意事项 |
|---|---|---|
>, >=, <, <= | 大小比较 | 支持数值、字符串、日期类型 |
= | 等于 | NULL 不安全,NULL = NULL结果为 NULL |
<=> | 等于 | NULL 安全,NULL <=> NULL结果为 TRUE |
!=, <> | 不等于 | NULL 不安全 |
BETWEEN a AND b | 范围匹配 | 闭区间[a, b] |
IN (v1, v2, ...) | 集合匹配 | 任意一个匹配即返回真 |
IS NULL | 判断为 NULL | 专门用于 NULL 值判断 |
IS NOT NULL | 判断不为 NULL | 专门用于 NULL 值判断 |
LIKE | 模糊匹配 | %匹配任意多个字符,_匹配任意 1 个字符 |
3.2 逻辑运算符
| 运算符 | 说明 |
|---|---|
AND | 逻辑与,所有条件同时满足才为真 |
OR | 逻辑或,任意一个条件满足即为真 |
NOT | 逻辑非,对条件结果取反 |
3.3 核心规则:WHERE 不可使用 SELECT 别名
你可能会疑惑,为什么WHERE里面不能使用别名?这就要从SQL的执行顺序说起了。在单表查询中,WHERE的执行阶段比SELECT更早。当WHERE执行时,列的别名还没有生成,因此它自然无法识别你定义的别名。
错误示例
-- 会报错,因为total这个别名在WHERE阶段还不存在 SELECT name, chinese + math + english total FROM exam_result WHERE total < 200;
正确写法
-- 在WHERE里,老老实实把完整的表达式写出来 SELECT name, chinese + math + english 总分 FROM exam_result WHERE chinese + math + english < 200;
3.4 筛选案例
-- 英语成绩不及格的同学 SELECT name, english FROM exam_result WHERE english < 60; -- 语文成绩在80到90分之间(BETWEEN是闭区间) SELECT name, chinese FROM exam_result WHERE chinese BETWEEN 80 AND 90; -- 数学成绩是58、59、98、99中的某一个 SELECT name, math FROM exam_result WHERE math IN (58, 59, 98, 99); -- 所有姓孙的同学 SELECT name FROM exam_result WHERE name LIKE '孙%'; -- 名字是两个字,并且姓孙 SELECT name FROM exam_result WHERE name LIKE '孙_'; -- 语文成绩大于80分,而且不姓孙 SELECT name, chinese FROM exam_result WHERE chinese > 80 AND name NOT LIKE '孙%'; -- 查询name字段为NULL的记录 SELECT * FROM test WHERE name IS NULL;
4 ~> ORDER BY 结果排序
4.1 排序基础
对查询结果进行排序时,ASC表示升序(默认选项,可以省略),DESC表示降序。这里需要特别留意NULL值的排序行为:在MySQL中,NULL被视为比所有非NULL值都小,因此升序时它排在最前面,降序时则排在最后面。
-- 数学成绩升序排列 SELECT name, math FROM exam_result ORDER BY math ASC; -- 数学成绩降序排列 SELECT name, math FROM exam_result ORDER BY math DESC;
4.2 多字段排序
排序时可以指定多个字段,优先级从左到右依次递减。先按照第一个字段排序,如果值相同,再按照第二个字段排序,以此类推。
-- 先按数学降序,数学同分则按英语升序,再同分则按语文升序 SELECT name, math, english, chinese FROM exam_result ORDER BY math DESC, english ASC, chinese ASC;
4.3 排序与别名
与WHERE不同,ORDER BY的执行阶段在SELECT之后,因此它可以正常使用SELECT中定义的别名。
-- 按总分降序排列,使用别名total让语义更清晰 SELECT name, chinese + math + english total FROM exam_result ORDER BY total DESC;
5 ~> LIMIT 分页筛选
5.1 三种语法形式
LIMIT用于截取查询结果,是实现分页的核心工具。请记住,在MySQL中行的下标从0开始。
-- 1. 取前3条 SELECT * FROM exam_result LIMIT 3; -- 2. 从下标1开始,取3条(也就是第2、3、4行) SELECT * FROM exam_result LIMIT 1, 3; -- 3. 标准写法,语义更清晰:取3条,偏移量为1(推荐) SELECT * FROM exam_result LIMIT 3 OFFSET 1;
5.2 分页业务实现
如果你想实现分页功能,有一个通用公式:第n页(页码从1开始),每页展示size条,那么偏移量就是(n - 1) * size。
-- 每页3条,查第2页数据 SELECT id, name, math, english, chinese FROM exam_result ORDER BY id LIMIT 3 OFFSET 3;
6 ~> 核心原理:单表 SQL 执行顺序
总结一下,一条SQL语句在单表查询时的逻辑执行顺序如下:
- FROM:首先确定数据来源于哪张表。
- WHERE:按照条件对行进行筛选。
- SELECT:确定最终返回哪些列,计算表达式,并生成别名。
- ORDER BY:对结果集进行排序。
- LIMIT:最后截取需要返回的行数。
这个顺序就是理解“别名能否使用”的关键:WHERE在SELECT之前执行,因此无法使用别名;而ORDER BY和LIMIT在SELECT之后执行,所以可以放心地使用别名。
