SQL 关键字速查总表
本文所有 SQL 关键字的中英文对照与作用速查,按主题分类整理。复习时先扫表建立索引,再回看正文加深记忆。
一、查询与条件筛选
| 关键字 | 中文 | 作用 |
|---|---|---|
| SELECT | 查询、选择 | 指定要返回的列 |
| FROM | 从 | 指定数据来源表 |
| AS | 作为、别名 | 给列或表起别名 |
| WHERE | 在哪里、条件 | 按条件筛选数据行 |
| AND | 与、并且 | 多个条件同时满足 |
| OR | 或、或者 | 多个条件满足其一 |
| NOT | 非、取反 | 对条件取反 |
| BETWEEN ... AND ... | 在......之间 | 判断区间范围(包含边界) |
| IN | 在......之中 | 匹配集合中的任意一个值 |
| LIKE | 像、模糊匹配 | 按模式做模糊查询 |
| IS NULL | 为空 | 判断字段值为 NULL |
| IS NOT NULL | 非空 | 判断字段值不为 NULL |
二、结果处理与排序 ORDER BY
| 关键字 | 中文 | 作用 |
|---|---|---|
| DISTINCT | 去重 | 对查询结果去重 |
| ORDER BY | 按......排序 | 对结果集排序 |
| ASC | 升序 | 从小到大排序(默认) |
| DESC | 降序 | 从大到小排序 |
| LIMIT | 限制、截断 | 截取指定条数结果 |
| OFFSET | 偏移 | 跳过若干行再取数 |
| CASE WHEN THEN ELSE END | 条件分支 | 类似 if-else,按条件生成新列 |
三、聚合与分组 GROUP BY
| 关键字 | 中文 | 作用 |
|---|---|---|
| COUNT | 计数 | 统计行数或非空值数量 |
| SUM | 求和 | 计算数值列之和 |
| AVG | 平均值 | 计算数值列平均 |
| MAX | 最大值 | 求最大值 |
| MIN | 最小值 | 求最小值 |
| GROUP BY | 分组 | 按字段分组后聚合 |
| HAVING | 分组后筛选 | 过滤分组结果 |
| GROUP_CONCAT | 分组拼接字符串 | 把组内多行值拼成一个串 |
| WITH ROLLUP | 小计与总计 | 追加小计行和总计行 |
四、关联查询 JOIN
| 关键字 | 中文 | 作用 |
|---|---|---|
| JOIN / INNER JOIN | 内连接 | 取两表能匹配的交集 |
| LEFT JOIN | 左连接 | 保留左表全部行 |
| RIGHT JOIN | 右连接 | 保留右表全部行 |
| FULL JOIN | 全连接 | 两表全部保留 |
| CROSS JOIN | 交叉连接 | 无条件笛卡尔积 |
| ON | 在......条件上 | 指定关联匹配条件 |
五、子查询与集合运算
| 关键字 | 中文 | 作用 |
|---|---|---|
| EXISTS | 存在 | 判断子查询是否存在匹配行 |
| NOT EXISTS | 不存在 | 判断子查询无匹配行 |
| ANY | 任意 | 满足子查询结果中任意一个即可 |
| ALL | 全部 | 必须满足子查询结果中所有值 |
| UNION | 并集 | 合并结果集并去重 |
| UNION ALL | 并集不去重 | 合并结果集保留重复行 |
| INTERSECT | 交集 | 取两个结果集的公共行 |
| EXCEPT | 差集 | 取前一个结果集独有行 |
六、开窗函数
| 关键字 | 中文 | 作用 |
|---|---|---|
| OVER | 窗口 | 定义开窗计算范围 |
| PARTITION BY | 按......分区 | 窗口内分组 |
| ORDER BY | 按......排序 | 窗口内排序 |
| ROW_NUMBER | 行号 | 分配连续唯一序号,不跳号 |
| RANK | 排名(跳号) | 并列同名次且跳号(1、1、3) |
| DENSE_RANK | 密集排名(不跳号) | 并列同名次且不跳号(1、1、2) |
| NTILE | 分桶 | 把结果平均分成 n 桶并编号 |
| LAG | 滞后 | 取当前行之前某行的值 |
| LEAD | 前导 | 取当前行之后某行的值 |
| FIRST_VALUE | 首值 | 取窗口内首行的值 |
| LAST_VALUE | 末值 | 取窗口内末行的值 |
| ROWS BETWEEN | 行范围 | 限定窗口帧范围 |
| UNBOUNDED PRECEDING | 组首 | 窗口帧从分组第一行开始 |
| CURRENT ROW | 当前行 | 窗口帧到当前行 |
七、常用函数 常用函数
| 关键字 | 中文 | 作用 |
|---|---|---|
| UPPER / LOWER | 大写 / 小写 | 字符串大小写转换 |
| LENGTH / CHAR_LENGTH | 长度 | 返回字节 / 字符长度 |
| CONCAT / CONCAT_WS | 拼接 | 连接多个字符串 |
| REPLACE | 替换 | 把子串替换为新串 |
| SUBSTRING | 截取子串 | 按位置截取子串 |
| LEFT / RIGHT | 左截取 / 右截取 | 截取左 / 右 n 个字符 |
| TRIM / LTRIM / RTRIM | 去空格 | 去除首尾 / 左 / 右空格 |
| INSTR / LOCATE | 定位子串 | 返回子串首次出现位置 |
| LPAD / RPAD | 左补齐 / 右补齐 | 把字符串补齐到指定长度 |
| REVERSE / REPEAT | 反转 / 重复 | 反转字符串 / 重复 n 次 |
| ROUND | 四舍五入 | 对数值四舍五入 |
| CEIL / FLOOR | 向上取整 / 向下取整 | 取整运算 |
| ABS | 绝对值 | 取绝对值 |
| MOD | 取余 | 求余数 |
| POWER | 幂运算 | 求幂 |
| DATE / DATETIME / TIME | 日期 / 日期时间 / 时间 | 获取当前日期、日期时间、时间 |
| NOW / CURDATE | 当前时间 / 当前日期 | 获取当前日期时间 / 当前日期 |
| DATE_FORMAT | 日期格式化 | 格式化日期输出 |
| DATEDIFF | 日期差 | 计算两个日期相差天数 |
| DATE_ADD / DATE_SUB | 日期加 / 日期减 | 对日期做加减运算 |
| YEAR / MONTH / DAY | 年 / 月 / 日 | 提取日期的年、月、日 |
| IFNULL | 空值替换 | 值为 NULL 时返回默认值 |
| COALESCE | 取首个非空 | 返回第一个非 NULL 值 |
| NULLIF | 相等转 NULL | 两值相等返回 NULL,否则返回值 1 |
| CAST / CONVERT | 类型转换 | 显式转换数据类型 |
八、数据写入与表结构
| 关键字 | 中文 | 作用 |
|---|---|---|
| INSERT INTO | 插入到 | 向表插入新数据行 |
| VALUES | 值 | 指定插入的具体值 |
| UPDATE | 更新 | 修改表中已有数据 |
| SET | 设置 | 指定要修改的列和新值 |
| DELETE | 删除 | 删除满足条件的行 |
| TRUNCATE | 清空 | 快速清空整表 |
| CREATE TABLE | 创建表 | 新建数据表 |
| ALTER TABLE | 修改表 | 变更表结构 |
| ADD COLUMN | 添加列 | 新增一列 |
| DROP COLUMN | 删除列 | 删除已有列 |
| MODIFY COLUMN | 修改列 | 修改列类型或属性 |
| RENAME TO | 重命名 | 修改表名 |
| DROP | 删除对象 | 删除表、视图、索引等 |
| PRIMARY KEY | 主键 | 唯一标识且非空 |
| UNIQUE | 唯一 | 值不允许重复 |
| NOT NULL | 非空 | 值不允许为空 |
| DEFAULT | 默认值 | 未指定值时的缺省值 |
| FOREIGN KEY | 外键 | 关联另一张表的列 |
| REFERENCES | 引用 | 指定外键引用的表和列 |
| CHECK | 检查 | 检查数据满足约束条件 |
| CREATE INDEX | 创建索引 | 提高查询速度 |
| CREATE VIEW | 创建视图 | 把查询保存为虚拟表 |
| BEGIN / COMMIT / ROLLBACK | 开启 / 提交 / 回滚 | 事务控制 |
| CREATE USER | 创建用户 | 新建数据库用户 |
| GRANT / REVOKE | 授权 / 回收权限 | 分配 / 回收用户权限 |
| AUTO_INCREMENT | 自增 | 自动递增生成编号 |
九、进阶查询
| 关键字 | 中文 | 作用 |
|---|---|---|
| WITH | 公共表表达式 CTE | 给查询命名成临时结果集 |
| WITH RECURSIVE | 递归查询 | 递归处理树形结构 |
| EXPLAIN | 执行计划 | 查看 SQL 执行计划,定位慢查询 |
SQL 基础
假定当前有一个数据库表
student,包含字段name、age、score等,后续示例均基于此表演示。
参考 SQL之母
一、基础查询 SELECT
1、全表查询 SELECT *
使用
SELECT * FROM 表名这样的 SQL 语句时,就是在进行全表查询。*代表所有列。
sql
SELECT * FROM 表名;
sql
SELECT * FROM student;
2、选择查询 SELECT
从数据表中选择特定的列或字段,并只返回这些列的数据值,语法为
SELECT 列名1, 列名2, ... FROM 表名。
sql
SELECT 列名1, 列名2, ...
FROM 表名;
从
student表中选出所有学生的姓名(name)和年龄(age):
sql
SELECT name, age FROM student;
3、别名 AS
使用别名语法
{原始字段名} AS {别名}来为查询结果的列名取一个便于理解的名称。
sql
SELECT 列名 AS 别名 [, 列名 AS 别名 ...] FROM 表名;
从
student表查询学生姓名(name)和年龄(age),并分别取别名为「学生姓名」和「学生年龄」:
sql
SELECT name AS '学生姓名', age AS '学生年龄' FROM student;
4、常量和运算 +、-、*、/ 算术运算符
在查询语句中可以对数据进行加减乘除、取平均值、连接文本等操作。
sql
SELECT 列名, 列名 + 值 AS 别名, 列名 - 值 AS 别名, 列名 * 值 AS 别名, 列名 / 值 AS 别名 FROM 表名;
从
student表中选出所有学生的姓名(name)和分数(score),并额外计算出分数的 2 倍:
sql
SELECT name, score, score * 2 AS double_score FROM student;
二、条件查询 WHERE
5、WHERE 条件筛选 WHERE
从数据库中筛选出满足特定条件的数据行。
从student表中选出学生姓名(name)和成绩(score),要求姓名等于'L':
sql
SELECT 列名 FROM 表名 WHERE 条件;
```> 从 `student` 表中选出学生姓名(name)和成绩(score),要求姓名等于 `'L'`:
```sql
SELECT name, score FROM student WHERE name = 'L';
6、运算符 =、!=、>=、<、>、BETWEEN
>=、!=、<、>等运算符可根据字段的不同取值进行灵活的筛选和过滤;区间判断可使用BETWEEN A AND B,表示落在 A 到 B 范围内(包含边界)。
sql
SELECT 列名
FROM 表名
WHERE 列名 >= 值
OR 列名 != 值
OR 列名 < 值
OR 列名 > 值
OR 列名 BETWEEN 值 AND 值; -- 区间判断,包含边界
从
student表中选出所有学生的姓名(name)和年龄(age),要求姓名不等于'L':
sql
SELECT name, age FROM student WHERE name != 'L';
7、空值判断 IS NULL、IS NOT NULL
使用
IS NULL、IS NOT NULL判断字段是否为空值或非空值。注意:判断空值不能用= NULL。
sql
SELECT 列名 FROM 表名 WHERE 列名 IS NULL;
SELECT 列名 FROM 表名 WHERE 列名 IS NOT NULL;
从
student表中选出姓名(name)、年龄(age)和成绩(score),要求年龄不为空:> 从student表中选出姓名(name)、年龄(age)和成绩(score),要求年龄不为空:
sql
SELECT name, age, score FROM student WHERE age IS NOT NULL;
8、模糊查询 LIKE
使用
LIKE关键字实现模糊查询,常用通配符:
- 百分号
%:表示任意长度的任意字符序列。 - 下划线
_:表示任意单个字符。
sql
SELECT 列名 FROM 表名 WHERE 列名 [NOT] LIKE 匹配模式;
从
student表中选出学生姓名(name)和成绩(score),要求姓名不包含"L":> 从student表中选出学生姓名(name)和成绩(score),要求姓名不包含"L":
sql
SELECT name, score FROM student WHERE name NOT LIKE '%L%';
9、逻辑运算 AND、OR、NOT
使用
AND、OR、NOT组合多个条件:AND同时满足、OR满足其一、NOT取反。
sql
SELECT 列名
FROM 表名
WHERE 条件1 AND 条件2;
SELECT 列名
FROM 表名
WHERE 条件1 OR 条件2;
SELECT 列名
FROM 表名
WHERE NOT 条件;
```> 使用 `AND`、`OR`、`NOT` 组合多个条件:`AND` 同时满足、`OR` 满足其一、`NOT` 取反。
> 从 `student` 表中选出学生姓名(name)和成绩(score),要求姓名包含 `"L"`,或者成绩大于 500:
```sql
SELECT name, score
FROM student
WHERE name LIKE '%L%' OR score > 500;
三、结果处理 DISTINCT/ORDER BY/LIMIT
10、去重 DISTINCT
使用
DISTINCT关键字对查询结果去重。当作用于多个列时,去重的是多列组合。
sql
SELECT DISTINCT 列名1, 列名2, ... FROM 表名;
从
student表中查询所有不重复的班级 ID(class_id)和考试编号(exam_num)组合:> 从student表中查询所有不重复的班级 ID(class_id)和考试编号(exam_num)组合:
sql
SELECT DISTINCT class_id, exam_num FROM student;
11、排序 ORDER BY 【ASC / DESC】
ORDER BY用于结果排序:ASC升序(从小到大,默认)、DESC降序(从大到小)。多字段排序语法为ORDER BY 字段1 [ASC|DESC], 字段2 [ASC|DESC], ...。
sql
SELECT 列名
FROM 表名
[WHERE 条件]
ORDER BY 排序字段 [ASC|DESC], 排序字段 [ASC|DESC];
查询学生姓名(name)、年龄(age)和成绩(score),按成绩从大到小排序,成绩相同时按年龄从小到大排序:
sql
SELECT name, age, score
FROM student
ORDER BY score DESC, age ASC;
13、截断和偏移 LIMIT
LIMIT用于截断查询结果:
LIMIT m:只取前 m 条。LIMIT n, m:跳过前 n 条后,再取 m 条(n 从 0 开始计数)。
sql
-- 通用语法模板
SELECT 列名
FROM 表名
[WHERE 条件]
[ORDER BY 排序字段 [ASC|DESC]]
LIMIT 条数; -- 只取前 N 条
SELECT 列名
FROM 表名
[WHERE 条件]
[ORDER BY 排序字段 [ASC|DESC]]
LIMIT 偏移量, 条数; -- 跳过前 N 条后,再取 M 条
从
student表查询学生姓名(name)和年龄(age),按年龄从小到大排序,从第 2 条开始截取 3 个学生:
sql
SELECT name, age
FROM student
ORDER BY age ASC
LIMIT 1, 3;
14、条件分支 CASE WHEN THEN ELSE END
CASE WHEN类似编程语言中的if else条件判断,可根据条件动态生成新列或对现有列进行转换。语法模板:
sql
SELECT
列名,
CASE
WHEN (条件1) THEN 结果1
WHEN (条件2) THEN 结果2
[WHEN (条件N) THEN 结果N ...]
[ELSE 其他结果]
END [AS 别名]
FROM 表名
[WHERE 条件]
[ORDER BY 排序字段 [ASC|DESC]];
将
student表按年龄划分为三个等级(age_level):60 岁以上为「老同学」,20 岁以上(不含 60 岁以上)为「年轻」,20 岁及以下或没有年龄信息为「小同学」。返回学生姓名(name)和年龄等级(age_level),并按姓名升序排序:
sql
SELECT
name,
CASE
WHEN (age > 60) THEN '老同学'
WHEN (age > 20) THEN '年轻'
ELSE '小同学'
END AS age_level
FROM student
ORDER BY name ASC;
38、分页查询 LIMIT 与排序稳定性 LIMIT
分页本质是
ORDER BY+LIMIT的组合。排序字段有重复值时结果顺序不稳定,建议追加唯一列(如id)作为兜底排序,保证翻页不重复、不遗漏。
sql
SELECT 列
FROM 表
[WHERE 条件]
ORDER BY 排序字段 [ASC|DESC], 唯一列 [ASC|DESC]
LIMIT 偏移量, 条数;
student表包含 id、name、score。按成绩降序分页,每页 10 条,取第 2 页:
sql
SELECT id, name, score
FROM student
ORDER BY score DESC, id ASC
LIMIT 10, 10;
四、函数 UPPER/LOWER/CONCAT/SUBSTRING/ROUND/CEIL/FLOOR/ABS/DATE_FORMAT/DATEDIFF
15、时间函数 DATE()、DATETIME()、TIME()
常用时间函数:
DATE():获取当前日期(如2023-08-01)。DATETIME():获取当前日期时间(如2023-08-01 14:30:00)。TIME():获取当前时间(如14:30:00)。
查询所有学生姓名(name)和当前日期,列名为「当前日期」:
sql
SELECT 列名, DATE() AS '别名' FROM 表名;
SELECT 列名, DATETIME() AS '别名' FROM 表名;
SELECT 列名, TIME() AS '别名' FROM 表名;
sql
SELECT name, DATE() AS '当前日期' FROM student;
16、字符串处理函数 UPPER/LOWER/CONCAT/SUBSTRING
常用字符串函数
UPPER(str):把字符串全部转换为大写。LOWER(str):把字符串全部转换为小写。LENGTH(str):返回字符串长度(字节数因数据库实现而异)。CHAR_LENGTH(str):返回字符个数,中文等多字节字符按 1 个字符计算。CONCAT(str1, str2, ...):拼接多个字符串;任一参数为NULL时,结果通常为NULL。CONCAT_WS(sep, str1, str2, ...):用分隔符sep拼接多个字符串,自动跳过NULL。REPLACE(str, from_str, to_str):把字符串中的from_str替换为to_str。SUBSTRING(str, pos, len):从pos位置开始截取len长度的子串,pos从 1 开始。LEFT(str, len)/RIGHT(str, len):分别截取字符串左侧 / 右侧len个字符。TRIM(str):去掉字符串首尾空格;LTRIM/RTRIM分别只去左侧 / 右侧空格。INSTR(str, substr):返回子串substr在str中首次出现的位置,找不到返回 0。LOCATE(substr, str):与INSTR作用相同,参数顺序相反。LPAD(str, len, pad)/RPAD(str, len, pad):用pad在左 / 右侧把字符串补齐到len长度。REVERSE(str):反转字符串。REPEAT(str, n):把字符串重复n次。
sql
SELECT 列名, UPPER(列名) AS 别名
FROM 表名
WHERE 条件;
student表包含 id(学号)、name(姓名)。查询姓名为'L'的学生,展示学号、姓名及大写姓名(upper_name):>student表包含 id(学号)、name(姓名)。查询姓名为'L'的学生,展示学号、姓名及大写姓名(upper_name):
sql
SELECT id, name, UPPER(name) AS upper_name
FROM student
WHERE name = 'L';
17、聚合函数 COUNT/SUM/AVG/MAX/MIN
聚合函数用于对数据集进行汇总计算,可执行计数、求和、平均值、最大值和最小值等操作,常与
GROUP BY配合使用以对分组后的数据做汇总分析。
sql
SELECT
COUNT(列名) AS 计数,
SUM(数值列名) AS 总和,
AVG(数值列名) AS 平均值,
MAX(列名) AS 最大值,
MIN(列名) AS 最小值
FROM 表名
[WHERE 条件]
[GROUP BY 分组字段];
常见聚合函数****常见聚合函数
COUNT:计算指定列的行数或非空值数量。SUM:计算数值列之和。AVG:计算数值列的平均值。MAX:求最大值。MIN:求最小值。
student表包含 id、name、class_id、score。查询全体学生的总成绩(total_score)、平均成绩(avg_score)、最高成绩(max_score)和最低成绩(min_score):
sql
SELECT
SUM(score) AS total_score,
AVG(score) AS avg_score,
MAX(score) AS max_score,
MIN(score) AS min_score
FROM student;
34、数学函数 ROUND/CEIL/FLOOR/ABS/MOD/POWER
常用数学函数:
ROUND四舍五入、CEIL向上取整、FLOOR向下取整、ABS绝对值、MOD取余、POWER幂运算。
sql
SELECT ROUND(数值, 小数位数) AS 四舍五入结果,
CEIL(数值) AS 向上取整结果,
FLOOR(数值) AS 向下取整结果,
ABS(数值) AS 绝对值结果,
MOD(被除数, 除数) AS 取余结果,
POWER(底数, 指数) AS 幂运算结果
FROM 表名;
student表包含 name、score。查询学生姓名和成绩四舍五入保留 1 位小数的结果:
sql
SELECT name, ROUND(score, 1) AS score_round
FROM student;
35、日期计算与格式化 DATE_FORMAT/DATEDIFF
常用日期函数:
NOW()当前时间、CURDATE()当前日期、DATE_FORMAT()格式化、DATEDIFF()相差天数、DATE_ADD()/DATE_SUB()日期加减、YEAR()/MONTH()/DAY()取年月日。
sql
-- 获取当前日期和时间
SELECT NOW();
SELECT CURDATE();
-- 格式化日期
SELECT DATE_FORMAT(日期, '%Y-%m-%d') FROM 表名;
-- 计算两个日期相差天数
SELECT DATEDIFF(日期1, 日期2);
-- 日期加减
SELECT DATE_ADD(日期, INTERVAL 偏移量 DAY) FROM 表名;
SELECT DATE_SUB(日期, INTERVAL 偏移量 DAY) FROM 表名;
-- 提取日期部分
SELECT YEAR(日期), MONTH(日期), DAY(日期) FROM 表名;
student表包含 name、birthday。查询学生姓名、出生年份,以及出生日期距离当前日期的天数:
sql
SELECT
name,
YEAR(birthday) AS birth_year,
DATEDIFF(CURDATE(), birthday) AS days_from_birth
FROM student;
36、空值处理 IFNULL / COALESCE / NULLIF
IFNULL(值, 默认值)在值为NULL时返回默认值;COALESCE(值1, 值2, ...)返回第一个非NULL的值;NULLIF(值1, 值2)两值相等时返回NULL,否则返回值1。
sql
-- 通用语法模板:空值处理函数
SELECT
IFNULL(列, 默认值) AS 别名, -- 列值为 NULL 时返回默认值
COALESCE(列1, 列2, ..., 默认值) AS 别名, -- 返回第一个非 NULL 的值
NULLIF(值1, 值2) AS 别名 -- 两值相等时返回 NULL,否则返回值1
FROM 表名
[WHERE 条件];
student表包含 name、score。查询学生姓名和成绩,成绩为空时显示 0:
sql
SELECT name, IFNULL(score, 0) AS score
FROM student;
37、类型转换 CAST / CONVERT
CAST(值 AS 类型)与CONVERT(值, 类型)用于显式转换数据类型,常见类型包括CHAR、SIGNED、DECIMAL、DATE、DATETIME。
sql
-- 通用语法模板:显式类型转换
CAST(值 AS 类型)
CONVERT(值, 类型)
student表包含 id、score。把学号转成字符串,成绩转成整数:
sql
SELECT
CAST(id AS CHAR) AS id_str,
CAST(score AS SIGNED) AS score_int
FROM student;
五、分组聚合 GROUP BY/HAVING
18、单字段分组 GROUP BY
GROUP BY用于对数据进行分类,并对每个分类做聚合计算。
student表包含 id、name、class_id、score。统计每个班级(class_id)的平均成绩(avg_score):
sql
SELECT 分组字段, 聚合函数(列名) AS 别名
FROM 表名
GROUP BY 分组字段;
sql
SELECT class_id, AVG(score) AS avg_score
FROM student
GROUP BY class_id;
19、多字段分组 GROUP BY
多字段分组按字段组合分类:
GROUP BY 字段1, 字段2。
sql
SELECT 分组字段1, 分组字段2, 聚合函数(列名) AS 别名
FROM 表名
[WHERE 条件]
GROUP BY 分组字段1, 分组字段2
[HAVING 分组后条件]
[ORDER BY 排序字段 [ASC|DESC]];
student表包含 id、name、class_id、exam_num、score。统计每个班级、每场考试的学生人数(total_num):
sql
SELECT class_id, exam_num, COUNT(*) AS total_num
FROM student
GROUP BY class_id, exam_num;
20、HAVING 子句
HAVING用于在分组聚合后对结果进行过滤。与WHERE的区别:WHERE在分组前过滤行,HAVING在分组后过滤分组。
sql
SELECT 分组字段, 聚合函数(列名) AS 别名
FROM 表名
GROUP BY 分组字段
HAVING 聚合函数(列名) 条件;
student表包含 id、name、class_id、score。查询总成绩超过 150 分的班级编号(class_id)和总成绩(total_score):>student表包含 id、name、class_id、score。查询总成绩超过 150 分的班级编号(class_id)和总成绩(total_score):
sql
SELECT class_id, SUM(score) AS total_score
FROM student
GROUP BY class_id
HAVING SUM(score) > 150;
51、GROUP_CONCAT 合并字符串
GROUP_CONCAT(列 SEPARATOR '分隔符')把同一分组内的多行值拼成一个字符串,常用于「一个班级所有学生姓名」这类展示。
sql
SELECT 分组字段, GROUP_CONCAT(列名 [ORDER BY 排序字段 [ASC|DESC]] SEPARATOR '分隔符') [AS 别名]
FROM 表名
[WHERE 条件]
GROUP BY 分组字段;
student表包含 name、class_id。查询每个班级的学生姓名,用逗号拼接:
sql
SELECT class_id, GROUP_CONCAT(name SEPARATOR ',') AS names
FROM student
GROUP BY class_id;
52、WITH ROLLUP 小计与总计 GROUP BY
GROUP BY ... WITH ROLLUP在分组结果后追加小计行和总计行,分组列为NULL的行即为汇总行。
sql
SELECT 分组字段, 聚合函数(列名)
FROM 表名
[WHERE 条件]
GROUP BY 分组字段 WITH ROLLUP
[HAVING 聚合条件]
[ORDER BY 排序字段 [ASC|DESC]]
[LIMIT 偏移量, 条数];
student表包含 class_id、score。统计每个班级总成绩并追加总计行:
sql
SELECT class_id, SUM(score) AS total
FROM student
GROUP BY class_id WITH ROLLUP;
六、关联查询 JOIN
21、CROSS JOIN
CROSS JOIN是一种最简单的关联查询,不需要任何匹配条件,直接把左表的每一行与右表的每一行组合,返回笛卡尔积,结果行数 = 左表行数 × 右表行数。
sql
SELECT 列名
FROM 表名1 [别名1]
CROSS JOIN 表名2 [别名2];
student表包含 id、name、age、class_id;class表包含 id、name。将两表所有行组合,返回学生姓名、学生年龄、班级编号和班级名称:
sql
SELECT
s.name AS student_name,
s.age AS student_age,
s.class_id AS class_id,
c.name AS class_name
FROM student s
CROSS JOIN class c;
22、INNER JOIN
INNER JOIN根据两个表之间的关联条件,只返回两边都能匹配的行,即交集。
sql
SELECT 列
FROM 表名1 [AS] 别名1
INNER JOIN 表名2 [AS] 别名2
ON 别名1.关联列 = 别名2.关联列
[WHERE 条件]
[GROUP BY 分组字段]
[HAVING 分组条件]
[ORDER BY 排序字段 [ASC|DESC]];
student表包含 id、name、age、class_id;class表包含 id、name、level。按班级编号匹配,返回学生姓名、年龄、班级编号、班级名称和班级级别:
sql
SELECT
s.name AS student_name,
s.age AS student_age,
s.class_id AS class_id,
c.name AS class_name,
c.level AS class_level
FROM student s
JOIN class c ON s.class_id = c.id;
31、LEFT JOIN / RIGHT JOIN / FULL JOIN
LEFT JOIN以左表为主,保留左表全部行,右表无匹配时补NULL;RIGHT JOIN以右表为主;FULL JOIN两表全部保留,任一侧无匹配补NULL(MySQL 不直接支持,可用LEFT JOIN UNION RIGHT JOIN模拟)。
sql
SELECT 列
FROM 表名 别名
LEFT JOIN 表名 别名 ON 别名.关联列 = 别名.关联列
[WHERE 条件]
[GROUP BY 分组字段]
[HAVING 分组条件]
[ORDER BY 排序字段 [ASC|DESC]]
[LIMIT 偏移量, 条数];
student表包含 id、name、class_id;class表包含 id、name。查询所有学生及其班级名称,没有班级的学生班级名称显示为空:
sql
SELECT s.name AS student_name, c.name AS class_name
FROM student s
LEFT JOIN class c ON s.class_id = c.id;
32、自连接 SELF JOIN
自连接把同一张表当成两张表关联,必须起两个别名,常用于查找上下级、同班同学、比某人分数高的人等关系。
sql
SELECT a.列, b.列
FROM 表 a
JOIN 表 b ON a.关联列 = b.关联列
[WHERE 条件]
[GROUP BY 分组字段]
[HAVING 分组条件]
[ORDER BY 排序字段 [ASC|DESC]]
[LIMIT 偏移量, 条数];
student表包含 id、name、class_id、score。查询与「张三」同班的其他学生姓名:
sql
SELECT b.name
FROM student a
JOIN student b ON a.class_id = b.class_id
WHERE a.name = '张三' AND b.name <> '张三';
33、多表关联 JOIN
三张及以上表关联时,继续用
JOIN ... ON ...依次拼接,每增加一张表就补充一个关联条件,避免因漏条件导致笛卡尔积。
sql
SELECT 列
FROM 表1 别名1
JOIN 表2 别名2 ON 别名1.关联列 = 别名2.关联列
JOIN 表3 别名3 ON 别名2.关联列 = 别名3.关联列
[WHERE 条件]
[GROUP BY 分组字段]
[HAVING 分组筛选条件]
[ORDER BY 排序字段 [ASC|DESC]]
[LIMIT 偏移量, 条数];
student(id、name、class_id)、class(id、name)、teacher(id、name、class_id)。查询学生姓名、班级名称和班主任姓名:
sql
SELECT
s.name AS student_name,
c.name AS class_name,
t.name AS teacher_name
FROM student s
JOIN class c ON s.class_id = c.id
JOIN teacher t ON t.class_id = c.id;
七、子查询 IN/EXISTS
23、子查询
子查询是嵌套在另一条 SQL 里的查询,用
()包裹,先执行内层查询,再执行外层查询。
1、标量子查询:返回一行一列 → 配合 =、>、< 等比较
sql
SELECT 列 FROM 表 WHERE 列 = (SELECT 单值 FROM 表 WHERE 条件);
2、列子查询:返回一列多行 → 配合 IN、NOT IN、ANY、ALL
sql
SELECT 列 FROM 表 WHERE 列 IN (SELECT 列 FROM 表 WHERE 条件);
3、EXISTS:只判断是否存在匹配行,内层通常写 SELECT 1
sql
SELECT 列
FROM 表 s
WHERE EXISTS (
SELECT 1 FROM 表 t WHERE t.列 = s.列
);
4、表子查询:返回多行多列 → 放在 FROM 后作为临时表,必须起别名
sql
SELECT 列
FROM (SELECT 列 FROM 表 WHERE 条件) AS t
WHERE 条件;
标量子查询速记
- 内层只返回一行一列时,外层才能用
=、>、<、>=、<=、!=直接比较。 - 常见单值来源:
AVG()、SUM()、MAX()、MIN()、COUNT(),或LIMIT 1。 - 内层返回多行会报错,此时应改用
IN或加LIMIT 1。
一句话要点
- 子查询必须加括号,
FROM里的子查询必须起别名。 - 标量子查询只能返回一行一列,否则报错。
- 能用
JOIN表达的优先用JOIN,性能更好。 - 嵌套不宜过深,否则可读性和性能都会下降。
student表包含 id、name、age、score、class_id;class表包含 id、name。使用子查询找出有对应班级的学生,返回姓名、分数和班级编号:
sql
SELECT name, score, class_id
FROM student
WHERE class_id IN (SELECT DISTINCT id FROM class);
24、EXISTS、NOT EXISTS
EXISTS用于检查主查询结果中是否存在满足条件的记录,返回布尔值;NOT EXISTS用于查找不满足存在条件的记录。
student表包含 id、name、age、score、class_id;class表包含 id、name。使用NOT EXISTS找出不存在对应班级的学生,返回姓名、年龄和班级编号:
sql
SELECT name, age, class_id
FROM student
WHERE NOT EXISTS (
SELECT 1 FROM class WHERE student.class_id = class.id
);
53、ANY / ALL
ANY表示与子查询结果中任意一个值比较成立即可;ALL表示必须与子查询结果中所有值比较都成立。> ANY等价于大于最小值,> ALL等价于大于最大值。
sql
WHERE 列 > ANY (SELECT 列 FROM 表 WHERE 条件)
WHERE 列 > ALL (SELECT 列 FROM 表 WHERE 条件)
student表包含 name、score。查询成绩高于「1 班任意一个学生」的学生:
sql
SELECT name, score
FROM student
WHERE score > ANY (
SELECT score FROM student WHERE class_id = 1
);
八、组合查询
25、UNION 和 UNION ALL
UNION合并多个查询结果集并去重;UNION ALL合并结果集但不去重。上下查询的列数、顺序和类型应保持一致。
student与student_new字段均为 id、name、age、score、class_id。查询两表所有学生的 name、age、score、class_id,并保留重复记录:
sql
SELECT name, age, score, class_id FROM student
UNION ALL
SELECT name, age, score, class_id FROM student_new;
54、INTERSECT / EXCEPT
INTERSECT取两个结果集的交集(去重);EXCEPT(Oracle 中为MINUS)取差集,即在前一个结果中但不在后一个结果中的行。MySQL 8.0 之前需用JOIN或IN模拟。
sql
SELECT ... INTERSECT SELECT ...;
SELECT ... EXCEPT SELECT ...;
查询既在
student又在student_new中出现的姓名:
sql
SELECT name FROM student
INTERSECT
SELECT name FROM student_new;
九、开窗函数
26、SUM OVER
开窗函数是一种强大的查询工具,可以在保留原始行明细的同时进行分组计算。聚合函数(如
SUM、AVG、COUNT)均可与OVER结合使用。
sql
SUM(计算字段名) OVER (PARTITION BY 分组字段名)
student表包含 id、name、age、class_id、score、exam_num。查询每个学生的详细信息,并计算每个班级的平均分:
sql
SELECT
id, name, age, class_id, score, exam_num,
AVG(score) OVER (PARTITION BY class_id) AS class_avg_score
FROM student;
27、SUM OVER ORDER BY
在分组基础上按顺序累加,实现同组数据的累计求和。
sql
SUM(计算字段名) OVER (
PARTITION BY 分组字段名 -- 可选:按这些字段分组
ORDER BY 排序字段 [ASC|DESC] -- 可选:组内排序方式
[ROWS BETWEEN 上边界 AND 下边界] -- 可选:窗口帧范围
)
student表包含 id、name、age、score、class_id。按分数升序,累计计算每个班级的学生总分(class_sum_score):
sql
SELECT
id, name, age, score, class_id,
SUM(score) OVER (
PARTITION BY class_id
ORDER BY score ASC
) AS class_sum_score
FROM student;
28、RANK
RANK用于对结果集排名;存在并列时保留相同名次,并跳过后续名次(如 1、1、3)。
sql
RANK() OVER (
PARTITION BY 列名1, 列名2, ... -- 可选,分组列
ORDER BY 列名3 [ASC|DESC], ... -- 排序列及排序方式
) AS rank_column
student表包含 id、name、age、score、class_id。按分数降序计算每个班级内学生的排名(ranking):
sql
SELECT
id, name, age, score, class_id,
RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS ranking
FROM student;
29、ROW_NUMBER
ROW_NUMBER为结果集中每一行分配唯一连续的序号,不会跳号(如 1、2、3)。
sql
ROW_NUMBER() OVER (
PARTITION BY column1, column2, ... -- 可选,分组列
ORDER BY column3 [ASC|DESC], ... -- 排序列及排序方式
) AS row_number_column
student表包含 id、name、age、score、class_id。按分数降序给每个班级内的学生分配编号(row_number):
sql
SELECT
id, name, age, score, class_id,
ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS row_number
FROM student;
30、LAG / LEAD
LAG/LEAD用于获取当前行之前 / 之后某一行的值,常用于相邻行比较或时间序列分析。
sql
LAG(column_name, offset, default_value) OVER (
PARTITION BY partition_column
ORDER BY sort_column
);
LEAD(column_name, offset, default_value) OVER (
PARTITION BY partition_column
ORDER BY sort_column
);
student表包含 id、name、age、score、class_id。按分数降序,获取每个班级内当前学生的上一名学生姓名(prev_name)和下一名学生姓名(next_name):
sql
SELECT
id,
name,
age,
score,
class_id,
LAG(name) OVER (PARTITION BY class_id ORDER BY score DESC) AS prev_name,
LEAD(name) OVER (PARTITION BY class_id ORDER BY score DESC) AS next_name
FROM student;
49、DENSE_RANK / NTILE / FIRST_VALUE
DENSE_RANK()并列同名次且不跳号(1、1、2);NTILE(n)把结果均分成 n 桶并编号;FIRST_VALUE(列)/LAST_VALUE(列)取窗口内首行 / 末行的值。
sql
DENSE_RANK() OVER (PARTITION BY 分组列 ORDER BY 排序列 DESC)
NTILE(n) OVER (ORDER BY 排序列)
FIRST_VALUE(列) OVER (PARTITION BY 分组列 ORDER BY 排序列)
student表包含 id、name、score、class_id。按班级给成绩排名,并列时不跳号:
sql
SELECT
id, name, score, class_id,
DENSE_RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS dr
FROM student;
50、窗口帧 ROWS BETWEEN
窗口帧用于限定「当前行参与计算的范围」:
ROWS BETWEEN n PRECEDING AND m FOLLOWING表示前 n 行到后 m 行;UNBOUNDED PRECEDING表示从组首开始。
sql
聚合函数(列) OVER (
PARTITION BY 分组列
ORDER BY 排序列
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
)
student表包含 id、name、score、class_id。计算每个学生与同班前一名的分数之和:
sql
SELECT
id, name, score, class_id,
SUM(score) OVER (
PARTITION BY class_id
ORDER BY score
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
) AS sum_two
FROM student;
十、数据写入与表结构
39、数据插入 INSERT
INSERT INTO 表 (列...) VALUES (值...)插入一行;一次写多组VALUES可批量插入;INSERT INTO 表 SELECT ...可把查询结果直接写入表。
sql
INSERT INTO 表 (列1, 列2) VALUES (值1, 值2);
INSERT INTO 表 (列1, 列2)
VALUES (值1, 值2), (值3, 值4);
INSERT INTO 表 (列1, 列2)
SELECT 列1, 列2 FROM 另一张表;
向
student表插入一条学生记录:
sql
INSERT INTO student (id, name, age, score, class_id)
VALUES (101, '张三', 20, 88.5, 1);
40、数据更新 UPDATE
UPDATE 表 SET 列 = 值 WHERE 条件修改满足条件的行。不写WHERE会更新全表 ,务必先用SELECT验证条件。
sql
UPDATE 表
SET 列1 = 值1, 列2 = 值2
WHERE 条件;
把
student表中姓名为「张三」的学生成绩改为 95:
sql
UPDATE student
SET score = 95
WHERE name = '张三';
41、数据删除 DELETE / TRUNCATE
DELETE FROM 表 WHERE 条件删除满足条件的行,可回滚、可带条件;TRUNCATE TABLE 表清空整表,速度快但不能回滚、不能带条件。
sql
DELETE FROM 表 WHERE 条件;
TRUNCATE TABLE 表;
删除
student表中成绩低于 60 的学生:
sql
DELETE FROM student WHERE score < 60;
42、建表 CREATE TABLE 与常用数据类型
建表时需指定列名、数据类型和约束。常用类型:
INT整数、DECIMAL(m,n)定点小数、VARCHAR(n)变长字符串、CHAR(n)定长字符串、DATE日期、DATETIME日期时间、TEXT长文本。
sql
CREATE TABLE 表名 (
列名 数据类型 [约束],
...
);
创建学生表
student:
sql
CREATE TABLE student (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT,
score DECIMAL(5,2) DEFAULT 0,
class_id INT,
birthday DATE
);
43、修改表结构 ALTER TABLE
ALTER TABLE用于增删改列、改类型、加约束:ADD COLUMN加列、DROP COLUMN删列、MODIFY COLUMN改类型、RENAME TO改表名。
sql
ALTER TABLE 表 ADD COLUMN 列 类型;
ALTER TABLE 表 DROP COLUMN 列;
ALTER TABLE 表 MODIFY COLUMN 列 新类型;
ALTER TABLE 表 RENAME TO 新表名;
给
student表增加一个性别列 gender:
sql
ALTER TABLE student ADD COLUMN gender VARCHAR(10);
44、约束 PRIMARY KEY / UNIQUE / NOT NULL / DEFAULT / FOREIGN KEY
约束用于保证数据完整性:
PRIMARY KEY主键唯一且非空、UNIQUE唯一、NOT NULL非空、DEFAULT默认值、FOREIGN KEY外键关联另一张表、CHECK检查条件。
sql
列名 类型 PRIMARY KEY
列名 类型 UNIQUE
列名 类型 NOT NULL DEFAULT 默认值
FOREIGN KEY (列) REFERENCES 另一张表(列)
创建班级表
class,并给学生表加外键关联班级:
sql
CREATE TABLE class (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
ALTER TABLE student
ADD CONSTRAINT fk_student_class
FOREIGN KEY (class_id) REFERENCES class(id);
45、索引 CREATE INDEX
索引用于加速查询,代价是占用空间、降低写入速度。
CREATE INDEX建普通索引,CREATE UNIQUE INDEX建唯一索引,DROP INDEX删除索引。
sql
CREATE INDEX 索引名 ON 表(列);
CREATE UNIQUE INDEX 索引名 ON 表(列);
DROP INDEX 索引名 ON 表;
给
student表的name列建索引:
sql
CREATE INDEX idx_student_name ON student(name);
46、视图 CREATE VIEW
视图是把一条查询保存成「虚拟表」,查询视图就像查询普通表,可简化复杂 SQL、控制字段暴露;视图本身不存数据,底层数据变化会同步体现。
sql
CREATE VIEW 视图名 AS SELECT ...;
DROP VIEW 视图名;
创建「班级平均分」视图:
sql
CREATE VIEW v_class_avg AS
SELECT class_id, AVG(score) AS avg_score
FROM student
GROUP BY class_id;
SELECT * FROM v_class_avg WHERE avg_score > 80;
47、事务 BEGIN / COMMIT / ROLLBACK
事务把多条语句打包成一个整体,要么全部成功、要么全部回滚。
BEGIN开启、COMMIT提交、ROLLBACK回滚,配合InnoDB引擎使用。
sql
BEGIN;
SQL 语句...;
COMMIT; -- 或 ROLLBACK;
转账场景:A 减 100、B 加 100,任一步失败则整体回滚:
sql
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;
48、常用 DCL 与权限管理
CREATE USER建用户、GRANT授权、REVOKE回收权限、DROP USER删除用户。生产环境应遵循最小权限原则。
sql
CREATE USER '用户名'@'主机' IDENTIFIED BY '密码';
GRANT 权限 ON 库.表 TO '用户名'@'主机';
REVOKE 权限 ON 库.表 FROM '用户名'@'主机';
创建一个只读用户并授予
student表的查询权限:
sql
CREATE USER 'reader'@'%' IDENTIFIED BY '123456';
GRANT SELECT ON demo.student TO 'reader'@'%';
十一、进阶查询
55、递归查询 WITH RECURSIVE
递归 CTE 用于处理树形结构(部门层级、评论盖楼)。结构为「初始查询 UNION ALL 递归查询」,递归部分引用自身,必须有终止条件。
sql
WITH RECURSIVE cte AS (
SELECT ... -- 初始行
UNION ALL
SELECT ... FROM 表 JOIN cte ON ... -- 递归行
)
SELECT * FROM cte;
部门表
dept(id、name、parent_id)。查询 id = 1 部门及其所有下级部门:
sql
WITH RECURSIVE dept_tree AS (
SELECT id, name, parent_id FROM dept WHERE id = 1
UNION ALL
SELECT d.id, d.name, d.parent_id
FROM dept d
JOIN dept_tree t ON d.parent_id = t.id
)
SELECT * FROM dept_tree;
56、公共表表达式 CTE(WITH)
WITH 名称 AS (查询)把一段查询命名成临时结果集,可被主查询多次引用,让嵌套子查询变扁平、可读性更好;多个 CTE 用逗号分隔。
sql
WITH cte1 AS (SELECT ...),
cte2 AS (SELECT ...)
SELECT * FROM cte1 JOIN cte2 ON ...;
student表包含 class_id、score。先算班级平均分,再筛出平均分大于 80 的班级:
sql
WITH class_avg AS (
SELECT class_id, AVG(score) AS avg_score
FROM student
GROUP BY class_id
)
SELECT * FROM class_avg WHERE avg_score > 80;
57、行转列与列转行
行转列:用
CASE WHEN或IF配合聚合函数,把「行上的分类值」变成「列」;列转行:用UNION ALL把多个列拆成多行。
sql
SUM(CASE WHEN 分类列 = '值' THEN 数值列 ELSE 0 END) AS 新列名
score_log表包含 name、subject、score。把语文、数学、英语三行转成三列:
sql
SELECT
name,
SUM(CASE WHEN subject = '语文' THEN score ELSE 0 END) AS chinese,
SUM(CASE WHEN subject = '数学' THEN score ELSE 0 END) AS math,
SUM(CASE WHEN subject = '英语' THEN score ELSE 0 END) AS english
FROM score_log
GROUP BY name;
58、排名取 Top N 的三种写法
取每组前 N 名是高频面试题,常见三种写法:开窗函数
ROW_NUMBER、关联子查询计数、GROUP_CONCAT+SUBSTRING_INDEX。推荐开窗函数,语义清晰、性能可控。
sql
SELECT * FROM (
SELECT 列,
ROW_NUMBER() OVER (PARTITION BY 分组列 ORDER BY 排序列 DESC) AS rn
FROM 表
) t
WHERE rn <= N;
student表包含 name、score、class_id。取每个班级成绩前 2 名:
sql
SELECT * FROM (
SELECT
name, score, class_id,
ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS rn
FROM student
) t
WHERE rn <= 2;
59、慢查询与执行计划 EXPLAIN
EXPLAIN查看 SQL 的执行计划,重点关注type(访问类型,ALL全表扫描最差,ref/range/index较好)、key(实际使用的索引)、rows(预估扫描行数)、Extra(是否出现Using filesort、Using temporary)。
sql
EXPLAIN SELECT ...;
查看按姓名查询学生时的执行计划:
sql
EXPLAIN SELECT * FROM student WHERE name = '张三';
60、SQL 书写规范与性能建议
好习惯比技巧更重要:列名写全、不用
SELECT *;条件列建索引;避免在索引列上做函数运算;LIKE不以%开头;批量操作用一条语句代替循环;大表分页用「延迟关联」或游标。
sql
-- 不推荐:对索引列做函数运算导致索引失效
WHERE DATE(create_time) = '2023-08-01'
-- 推荐:范围查询走索引
WHERE create_time >= '2023-08-01' AND create_time < '2023-08-02'
大表分页优化:先用索引列取出主键,再回表取数据:
sql
SELECT s.*
FROM student s
JOIN (
SELECT id FROM student ORDER BY id LIMIT 100000, 10
) t ON s.id = t.id;
速记总览:一句话 + 语法模板
按上文分类顺序整理,每条只保留「记忆点」和「可套用的语法骨架」,复习时先看记忆点,再默写模板。
一、基础查询
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 1 | 全表查询:星号代表所有列 | SELECT * FROM 表名; |
| 2 | 选择查询:只取想要的列 | SELECT 列1, 列2 FROM 表名; |
| 3 | 别名 AS:给结果列换个好懂的名字 | SELECT 列 AS '别名' FROM 表名; |
| 4 | 常量与运算:查询时可直接计算 | SELECT 列, 列 * 2 AS 新列 FROM 表名; |
二、条件查询
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 5 | WHERE:按行筛选,只留满足条件的行 | SELECT 列 FROM 表名 WHERE 条件; |
| 6 | 比较运算符:> < >= <= !=,范围用 BETWEEN A AND B |
WHERE 列 != 值 / WHERE 列 BETWEEN A AND B |
| 7 | 空值判断:空值不能用 =,要用 IS NULL |
WHERE 列 IS NULL / WHERE 列 IS NOT NULL |
| 8 | 模糊查询:% 任意多字符,_ 单个字符 |
WHERE 列 LIKE '%关键字%' / WHERE 列 NOT LIKE '%关键字%' |
| 9 | 逻辑运算:AND 同时满足,OR 满足其一,NOT 取反 | WHERE 条件1 AND 条件2 / WHERE 条件1 OR 条件2 / WHERE NOT 条件 |
三、结果处理
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 10 | 去重:DISTINCT 作用于整行组合 | SELECT DISTINCT 列1, 列2 FROM 表名; |
| 11 | 排序:ASC 升序(默认)、DESC 降序,多字段依次比较 | ORDER BY 列1 DESC, 列2 ASC |
| 13 | 截断偏移:LIMIT m 取前 m 条;LIMIT n, m 跳过 n 条再取 m 条 |
LIMIT m / LIMIT n, m |
| 14 | 条件分支:类似 if-else,从上往下匹配,命中即止 | CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 ELSE 其他 END AS 新列 |
| 38 | 分页:ORDER BY + LIMIT,排序字段有重复值时追加唯一列兜底 |
ORDER BY 排序列, 唯一列 LIMIT 偏移量, 条数 |
四、函数
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 15 | 时间函数:DATE 日期、DATETIME 日期时间、TIME 时间 | SELECT DATE() AS 当前日期 FROM 表名; |
| 16 | 字符串函数:大小写、长度、拼接、截取、替换、去空格 | UPPER(str) / LOWER(str) / CONCAT(a, b) / SUBSTRING(str, pos, len) / REPLACE(str, 旧, 新) / TRIM(str) |
| 17 | 聚合函数:多行压成一行,常配 GROUP BY | SELECT COUNT(*), SUM(列), AVG(列), MAX(列), MIN(列) FROM 表名; |
| 34 | 数学函数:四舍五入、取整、绝对值、取余、幂 | ROUND(数值, n) / CEIL(x) / FLOOR(x) / ABS(x) / MOD(a, b) / POWER(a, b) |
| 35 | 日期计算:格式化、相差天数、日期加减、取年月日 | DATE_FORMAT(日期, '%Y-%m-%d') / DATEDIFF(d1, d2) / DATE_ADD(日期, INTERVAL n DAY) / YEAR(日期) |
| 36 | 空值处理:IFNULL 给默认值、COALESCE 取第一个非空、NULLIF 相等转 NULL | IFNULL(列, 默认值) / COALESCE(列1, 列2, 默认值) / NULLIF(列, 值) |
| 37 | 类型转换:显式转字符串、整数、小数、日期 | CAST(值 AS 类型) / CONVERT(值, 类型) |
五、分组聚合
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 18 | 单字段分组:每个分组出一行 | SELECT 分组列, AVG(列) FROM 表名 GROUP BY 分组列; |
| 19 | 多字段分组:按字段组合分组 | SELECT 列1, 列2, COUNT(*) FROM 表名 GROUP BY 列1, 列2; |
| 20 | HAVING:分组之后再过滤;WHERE 在分组前,HAVING 在分组后 | GROUP BY 列 HAVING 聚合条件 |
| 51 | GROUP_CONCAT:把组内多行值拼成一个字符串 | SELECT 分组列, GROUP_CONCAT(列 SEPARATOR ',') FROM 表名 GROUP BY 分组列; |
| 52 | WITH ROLLUP:分组结果后追加小计行和总计行 | GROUP BY 分组列 WITH ROLLUP |
六、关联查询
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 21 | CROSS JOIN:无条件笛卡尔积,行数 = 左表行数 × 右表行数 | SELECT * FROM A CROSS JOIN B; |
| 22 | INNER JOIN:按关联条件取交集 | SELECT 列 FROM A a JOIN B b ON a.关联列 = b.关联列; |
| 31 | LEFT / RIGHT / FULL JOIN:left 保左表、right 保右表、full 两边都保,缺的补 NULL |
FROM A a LEFT JOIN B b ON a.列 = b.列 / RIGHT JOIN / FULL JOIN |
| 32 | 自连接:同一张表起两个别名互相关联 | FROM 表 a JOIN 表 b ON a.列 = b.列 WHERE 条件 |
| 33 | 多表关联:每加一张表补一个 ON,漏条件会变笛卡尔积 |
FROM A a JOIN B b ON a.列 = b.列 JOIN C c ON b.列 = c.列 |
七、子查询
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 23 | 子查询:括号包裹,先内后外;标量配 =,列子查询配 IN,表子查询放 FROM 且必须起别名 |
WHERE 列 = (SELECT 单值 ...) / WHERE 列 IN (SELECT 列 ...) / FROM (SELECT ...) AS t |
| 24 | EXISTS / NOT EXISTS:只判断有没有行,内层写 SELECT 1 |
WHERE EXISTS (SELECT 1 FROM B WHERE B.列 = A.列) / WHERE NOT EXISTS (...) |
| 53 | ANY / ALL:> ANY 大于最小值,> ALL 大于最大值 |
WHERE 列 > ANY (SELECT 列 FROM 表 WHERE 条件) / > ALL (...) |
八、组合查询
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 25 | UNION 去重合并,UNION ALL 保留重复;上下查询列数、类型要一致 | SELECT ... UNION ALL SELECT ... |
| 54 | INTERSECT 取交集,EXCEPT 取差集 | SELECT ... INTERSECT SELECT ... / SELECT ... EXCEPT SELECT ... |
九、开窗函数
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 26 | SUM OVER:分组内汇总,但保留每一行明细 | 聚合函数(列) OVER (PARTITION BY 分组列) |
| 27 | SUM OVER ORDER BY:组内按顺序累加,实现累计求和 | SUM(列) OVER (PARTITION BY 分组列 ORDER BY 排序列 ASC) |
| 28 | RANK:并列同名次,后续名次跳号(1、1、3) | RANK() OVER (PARTITION BY 分组列 ORDER BY 排序列 DESC) AS ranking |
| 29 | ROW_NUMBER:连续唯一编号,不跳号(1、2、3) | ROW_NUMBER() OVER (PARTITION BY 分组列 ORDER BY 排序列 DESC) AS rn |
| 30 | LAG / LEAD:取上一行 / 下一行的值,可设偏移和默认值 | LAG(列, offset, default) OVER (PARTITION BY 分组列 ORDER BY 排序列) / LEAD(...) OVER (...) |
| 49 | DENSE_RANK / NTILE / FIRST_VALUE:并列不跳号 / 均分 n 桶 / 取窗口首行 | DENSE_RANK() OVER (...) / NTILE(n) OVER (...) / FIRST_VALUE(列) OVER (...) |
| 50 | 窗口帧:限定当前行参与计算的范围 | 聚合函数(列) OVER (... ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) |
十、数据写入与表结构
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 39 | INSERT:插入一行 / 批量插入 / 查询结果写入表 | INSERT INTO 表 (列...) VALUES (值...); |
| 40 | UPDATE:改数据必须带 WHERE,否则全表更新 | UPDATE 表 SET 列 = 值 WHERE 条件; |
| 41 | DELETE / TRUNCATE:DELETE 可带条件可回滚,TRUNCATE 清空整表不可回滚 | DELETE FROM 表 WHERE 条件; / TRUNCATE TABLE 表; |
| 42 | CREATE TABLE:建表指定列名、类型、约束 | CREATE TABLE 表 (列 类型 约束, ...); |
| 43 | ALTER TABLE:加列、删列、改类型、改表名 | ALTER TABLE 表 ADD COLUMN 列 类型; |
| 44 | 约束:主键唯一非空,外键关联他表 | PRIMARY KEY / UNIQUE / NOT NULL DEFAULT 默认值 / FOREIGN KEY (列) REFERENCES 表(列) |
| 45 | 索引:加速查询,代价是占空间、降写入 | CREATE INDEX 索引名 ON 表(列); |
| 46 | 视图:把查询保存为虚拟表,不存数据 | CREATE VIEW 视图名 AS SELECT ...; |
| 47 | 事务:BEGIN 开启、COMMIT 提交、ROLLBACK 回滚 | BEGIN; ... COMMIT; / BEGIN; ... ROLLBACK; |
| 48 | DCL:建用户、授权、回收权限 | CREATE USER / GRANT / REVOKE |
十一、进阶查询
| 序号 | 记忆点 | 语法模板 |
|---|---|---|
| 55 | 递归 CTE:初始行 UNION ALL 递归行,必须有终止条件 | WITH RECURSIVE cte AS (初始 UNION ALL 递归) SELECT * FROM cte; |
| 56 | CTE(WITH):给查询命名成临时结果集,可多处引用 | WITH cte AS (SELECT ...) SELECT * FROM cte; |
| 57 | 行转列:CASE WHEN + 聚合;列转行:UNION ALL | SUM(CASE WHEN 分类列 = '值' THEN 数值列 ELSE 0 END) AS 列名 |
| 58 | Top N:ROW_NUMBER 开窗最推荐,语义清晰 | SELECT * FROM (SELECT ..., ROW_NUMBER() OVER (...) AS rn FROM 表) t WHERE rn <= N; |
| 59 | EXPLAIN:看 type、key、rows、Extra 定位慢查询 | EXPLAIN SELECT ...; |
| 60 | 书写规范:列名写全、索引列不套函数、LIKE 不以 % 开头 | WHERE create_time >= '...' AND create_time < '...' |
十二、执行顺序速记
写 SQL 的顺序和数据库执行的顺序并不一致,记住下面这条链,很多「为什么这里不能写别名」的问题就通了:
#mermaid-svg-ad3pJIxCzgC3Rt8W{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ad3pJIxCzgC3Rt8W .error-icon{fill:#552222;}#mermaid-svg-ad3pJIxCzgC3Rt8W .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ad3pJIxCzgC3Rt8W .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .marker.cross{stroke:#333333;}#mermaid-svg-ad3pJIxCzgC3Rt8W svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ad3pJIxCzgC3Rt8W p{margin:0;}#mermaid-svg-ad3pJIxCzgC3Rt8W .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .cluster-label text{fill:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .cluster-label span{color:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .cluster-label span p{background-color:transparent;}#mermaid-svg-ad3pJIxCzgC3Rt8W .label text,#mermaid-svg-ad3pJIxCzgC3Rt8W span{fill:#333;color:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .node rect,#mermaid-svg-ad3pJIxCzgC3Rt8W .node circle,#mermaid-svg-ad3pJIxCzgC3Rt8W .node ellipse,#mermaid-svg-ad3pJIxCzgC3Rt8W .node polygon,#mermaid-svg-ad3pJIxCzgC3Rt8W .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .rough-node .label text,#mermaid-svg-ad3pJIxCzgC3Rt8W .node .label text,#mermaid-svg-ad3pJIxCzgC3Rt8W .image-shape .label,#mermaid-svg-ad3pJIxCzgC3Rt8W .icon-shape .label{text-anchor:middle;}#mermaid-svg-ad3pJIxCzgC3Rt8W .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .rough-node .label,#mermaid-svg-ad3pJIxCzgC3Rt8W .node .label,#mermaid-svg-ad3pJIxCzgC3Rt8W .image-shape .label,#mermaid-svg-ad3pJIxCzgC3Rt8W .icon-shape .label{text-align:center;}#mermaid-svg-ad3pJIxCzgC3Rt8W .node.clickable{cursor:pointer;}#mermaid-svg-ad3pJIxCzgC3Rt8W .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .arrowheadPath{fill:#333333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ad3pJIxCzgC3Rt8W .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ad3pJIxCzgC3Rt8W .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ad3pJIxCzgC3Rt8W .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ad3pJIxCzgC3Rt8W .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .cluster text{fill:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W .cluster span{color:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ad3pJIxCzgC3Rt8W .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ad3pJIxCzgC3Rt8W rect.text{fill:none;stroke-width:0;}#mermaid-svg-ad3pJIxCzgC3Rt8W .icon-shape,#mermaid-svg-ad3pJIxCzgC3Rt8W .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ad3pJIxCzgC3Rt8W .icon-shape p,#mermaid-svg-ad3pJIxCzgC3Rt8W .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ad3pJIxCzgC3Rt8W .icon-shape .label rect,#mermaid-svg-ad3pJIxCzgC3Rt8W .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ad3pJIxCzgC3Rt8W .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ad3pJIxCzgC3Rt8W .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ad3pJIxCzgC3Rt8W :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} FROM / JOIN 取表
WHERE 行过滤
GROUP BY 分组
HAVING 组过滤
SELECT 取列与计算
DISTINCT 去重
ORDER BY 排序
LIMIT 截断
一句话口诀:表 → 行 → 组 → 组筛 → 列 → 去重 → 排序 → 截断。
十三、易错点清单
- 空值判断只能用
IS NULL/IS NOT NULL,写= NULL永远不成立。 WHERE里不能直接使用聚合函数,聚合条件要放到HAVING。SELECT中的非聚合列必须出现在GROUP BY里(标准 SQL 要求)。LIMIT n, m的n是「跳过的条数」,从 0 开始算,所以「从第 2 条开始」写LIMIT 1, 3。UNION会自动去重并排序,有性能开销;确定无重复时用UNION ALL。- 开窗函数不会减少行数,聚合函数不加
OVER会把多行压成一行,两者别混用。 RANK跳号、ROW_NUMBER不跳号、DENSE_RANK不跳号但并列同名次,按需求选。UPDATE、DELETE不带WHERE会作用于全表,执行前先SELECT验证条件。FROM后的子查询必须起别名,否则语法报错。- 多表关联漏写
ON条件会退化成笛卡尔积,结果行数爆炸。