一、核心基础语法(ES6+ 全支持)
| 语法类型 | 示例代码 | 说明 |
|---|---|---|
| 箭头函数 | pm.test("测试名称", () => { ... }) |
替代传统function,简洁(你截图中的写法✅) |
| 变量声明 | const res = pm.response.json(); |
const(常量)/let(变量),替代var |
| 解构赋值 | const { code, data } = res; |
快速提取响应 JSON 中的字段 |
| 模板字符串 | console.log(状态码:${pm.response.code}); |
拼接字符串更优雅 |
二、高频测试场景语法
1. 响应状态码 / 格式校验
javascript
运行
// 箭头函数极简写法(单行)
pm.test("响应码为200", () => pm.response.to.have.status(200));
pm.test("响应为JSON格式", () => pm.response.to.be.json);
// 多行逻辑(箭头函数)
pm.test("响应码非500", () => {
const status = pm.response.code;
pm.expect(status).to.not.equal(500); // 断言语法
});
2. 响应 JSON 字段校验
javascript
运行
pm.test("校验返回数据", () => {
const res = pm.response.json(); // 解析JSON响应
// 基础断言
pm.expect(res.code).to.equal(0); // 校验code为0
pm.expect(res.data).to.not.be.empty; // 校验data非空
pm.expect(res.msg).to.include("成功"); // 包含指定文本
// 数组/对象校验(箭头函数遍历)
res.data.list.forEach(item => {
pm.expect(item.id).to.be.a("number"); // 类型校验
pm.expect(item.name).to.not.be.null; // 非空校验
});
});
3. 环境变量 / 全局变量操作
javascript
运行
pm.test("设置/获取变量", () => {
// 设置变量(箭头函数简化赋值逻辑)
const setToken = (token) => pm.environment.set("token", token);
setToken(pm.response.json().data.token);
// 获取变量
const token = pm.environment.get("token");
pm.expect(token).to.be.a("string"); // 校验变量类型
});
4. 接口请求时间校验
javascript
运行
pm.test("响应时间<500ms", () => {
const checkTime = (time) => time < 500; // 箭头函数封装判断逻辑
pm.expect(checkTime(pm.response.responseTime)).to.be.true;
});
三、注意事项
- Postman 脚本环境完全支持 ES6+,箭头函数、Promise、async/await 等均可用;
- 单行逻辑用箭头函数更简洁(如你截图中的写法),多行逻辑建议加
{}保持可读性; - 断言库基于
Chai.js,语法支持expect/should/assert三种风格,优先用expect(最直观)。
javascript
以 Postman 的天气接口断言代码为例,拆解每一行的意思:
javascript
运行
// 1. 验证响应码为200(请求成功)
pm.test("响应码为200", function () {
pm.response.to.have.status(200);
});
pm:Postman 的内置对象(可以理解为 “Postman 工具的工具箱”),所有操作都靠它;pm.test("测试名称", 函数):定义一个测试用例,第一个参数是测试名称(随便写,方便看结果),第二个参数是要执行的测试逻辑;pm.response:代表接口的响应数据(比如状态码、响应体);to.have.status(200):判断响应码是否等于 200(Postman 封装好的语法,不用自己写判断)。
javascript
运行
// 2. 验证返回数据包含“北京”(城市正确)
pm.test("返回数据包含目标城市", function () {
pm.expect(pm.response.text()).to.include("北京");
});
pm.response.text():把接口的响应体转换成文本格式;pm.expect(内容).to.include("北京"):判断文本里是否包含 “北京”(类似 Excel 的 “查找” 功能)。
javascript
运行
// 3. 验证返回数据包含天气核心字段(如温度、日期)
pm.test("返回数据包含天气核心字段", function () {
const resData = pm.response.json(); // 把响应体转成JSON对象(方便按字段取值)
pm.expect(resData.result).to.have.property("date"); // 检查是否有“date”字段
pm.expect(resData.result).to.have.property("temperature"); // 检查是否有“temperature”字段
});
const resData = pm.response.json():把 JSON 格式的响应体转成 JS 对象(比如响应是{"result":{"date":"2025-12-24"}},转成对象后可以用resData.result.date直接取日期);have.property("date"):判断resData.result这个对象里是否有 “date” 这个属性(字段)。
三、核心结论(不用死记,会用就行)
- 不用把 JS 学透:接口测试里只用 Postman/JMeter 封装好的几个核心 API(
pm.test/pm.expect/pm.response),记熟这几个就能覆盖 90% 的场景; - 代码的本质是 “工具的配置”:这些 JS 代码不是 “编程开发”,只是用简单的语法告诉工具 “要验证什么”,比如 “检查响应码是不是 200”“有没有北京这个字”;
- 新手先抄后改:先复制现成的代码,把 “北京” 改成你要测的城市,把 “date” 改成你要验证的字段,用熟了再理解语法。
如果需要,我可以帮你整理一份接口测试常用 JS 代码速查表(只有 10 行核心代码,背下来就能
接口测试常用 JavaScript 代码速查表(Postman 专属)
核心覆盖 90% 接口测试场景,无需懂复杂语法,复制 + 改关键词即可用,新手直接上手。
| 测试场景 | 核心代码(直接复制) | 修改说明 |
|---|---|---|
| 验证响应码为 200 | javascript pm.test("响应码为200", function () { pm.response.to.have.status(200); }); |
把 200 改成目标状态码(如 400/500) |
| 验证响应包含指定文本 | javascript pm.test("包含目标文本", function () { pm.expect(pm.response.text()).to.include("北京"); }); |
把 “北京” 改成要验证的文本 |
| 验证 JSON 字段存在 | javascript pm.test("字段存在", function () { const res = pm.response.json(); pm.expect(res.result).to.have.property("date"); }); |
改res.result和date为目标字段路径 |
| 验证 JSON 字段值等于指定值 | javascript pm.test("字段值正确", function () { const res = pm.response.json(); pm.expect(res.result.risk_level).to.eql("高"); }); |
改risk_level和 “高” 为目标字段 / 值 |
| 提取变量到环境变量 | javascript const res = pm.response.json(); pm.environment.set("token", res.data.token); |
改token和res.data.token为目标变量 / 路径 |
| 验证响应时间<500ms | javascript pm.test("响应时间达标", function () { pm.expect(pm.response.responseTime).to.be.below(500); }); |
把 500 改成目标响应时间(毫秒) |
| 验证响应格式为 JSON | javascript pm.test("响应为JSON格式", function () { pm.response.to.be.json; }); |
无需修改,直接用 |
| 验证请求头包含指定值 | javascript pm.test("请求头正确", function () { pm.expect(pm.response.headers.get("Content-Type")).to.eql("application/json"); }); |
改Content-Type和值为目标头 |
| 接口依赖 - 引用环境变量 | 无需代码,URL/Body 中写{{变量名}}(如{{token}}) |
变量名需和提取时的名称一致 |
| 异常场景 - 验证 400 错误 | javascript pm.test("参数错误返回400", function () { pm.response.to.have.status(400); pm.expect(pm.response.text()).to.include("参数错误"); }); |
改 400 和 “参数错误” 为目标状态 / 文本 |
用法说明(新手必看)
- 所有代码粘贴到 Postman 的「Tests」标签页;
- 执行请求后,在「Test Results」中查看是否通过;
- 核心改法:只改代码中引号里的关键词(如 “北京”“date”“高”),其他代码不用动;
- 示例:验证 “空气质量接口返回 PM2.5 字段”,只需把 “date” 改成 “pm25” 即可。
实战示例(天气接口全套验证)
javascript
运行
// 1. 基础验证
pm.test("响应码200", () => pm.response.to.have.status(200));
pm.test("响应是JSON", () => pm.response.to.be.json);
pm.test("包含城市名", () => pm.expect(pm.response.text()).to.include("上海"));
// 2. 字段验证
const res = pm.response.json();
pm.test("有温度字段", () => pm.expect(res.result).to.have.property("temperature"));
pm.test("温度值合理", () => pm.expect(res.result.temperature).to.not.eql(""));
// 3. 提取变量(供下一个接口用)
pm.environment.set("city", res.result.city);
断言
接口断言是验证接口返回结果是否符合预期的核心步骤,不同场景下断言维度不同,但核心原则是:覆盖 “基础可用性 + 业务正确性 + 数据合法性”。以下是接口测试中必加的断言维度(按优先级排序),附具体示例和适用场景,新手可直接照搬:
一、核心断言维度(所有接口必加)
| 断言维度 | 作用 | 示例代码(Postman/JS) | 适用所有接口的原因 |
|---|---|---|---|
| 响应状态码 | 验证接口请求是否 “基础成功” | javascript pm.test("响应码200", () => pm.response.to.have.status(200)); |
状态码是接口最基础的健康度,200 = 成功,4xx = 参数错,5xx = 服务错 |
| 响应格式 | 验证返回数据格式符合约定 | javascript pm.test("响应为JSON", () => pm.response.to.be.json); |
接口通常约定返回 JSON/XML,格式错会导致下游解析失败 |
| 业务成功标识 | 验证接口 “业务逻辑” 成功(非仅请求成功) | javascript const res = pm.response.json(); pm.test("业务成功", () => pm.expect(res.code).to.eql(0)); |
状态码 200 不代表业务成功(如查无数据仍返回 200,但 code=1) |
二、业务层断言维度(按场景补充)
1. 数据存在性 / 正确性(查询 / 新增 / 修改接口必加)
| 场景 | 断言代码示例 |
|---|---|
| 包含指定文本 / 字段 | javascript // 包含目标城市 pm.expect(pm.response.text()).to.include("北京"); // 包含核心字段 pm.expect(res.result).to.have.property("temperature"); |
| 字段值等于预期 | javascript // 风险等级为“高” pm.expect(res.result.risk_level).to.eql("高"); // 新增后ID非空 pm.expect(res.data.id).to.not.be.empty; |
| 字段值范围合法 | javascript // 金额≥0 pm.expect(res.data.amount).to.be.at.least(0); // 响应时间<1s pm.expect(pm.response.responseTime).to.be.below(1000); |
2. 数据一致性(依赖接口 / 批量接口必加)
| 场景 | 断言代码示例 |
|---|---|
| 入参和返参一致 | javascript // 传入的客户ID和返回的一致 const reqCity = pm.request.url.query.get("city"); pm.expect(res.result.city).to.eql(reqCity); |
| 多接口数据一致 | javascript // 上一个接口提取的token,当前接口返回包含该token pm.expect(res.data.token).to.eql(pm.environment.get("token")); |
3. 异常场景断言(边界 / 错误用例必加)
| 场景 | 断言代码示例 |
|---|---|
| 参数缺失返回 400 | javascript pm.test("参数缺失返回400", () => pm.response.to.have.status(400)); pm.expect(res.msg).to.include("参数不能为空"); |
| 无权限返回 401 | javascript pm.test("无权限返回401", () => pm.response.to.have.status(401)); pm.expect(res.msg).to.include("未授权"); |
三、不同类型接口的断言清单(直接套用)
| 接口类型 | 必加断言维度 | 示例(银行场景) |
|---|---|---|
| 查询接口(GET) | 状态码 + 格式 + 业务成功 + 字段存在 + 值正确 | 查客户风险等级:验证返回 risk_level = 高、包含 customer_id |
| 新增接口(POST) | 状态码 + 格式 + 业务成功 + 新增 ID 非空 + 入参一致 | 新增客户:验证返回 customer_id、name 和传入一致 |
| 修改接口(PUT) | 状态码 + 格式 + 业务成功 + 修改后字段值更新 | 修改客户资产:验证 asset_amount = 修改后的值 |
| 删除接口(DELETE) | 状态码 + 格式 + 业务成功 + 查询不到该数据 | 删除客户:验证再次查询返回 “无数据” |
| 批量接口 | 状态码 + 格式 + 业务成功 + 返回条数符合预期 | 批量查 10 个客户:验证返回数组长度 = 10 |
四、断言设计技巧(新手避坑)
- 不要断言 “无关字段”:只验证核心业务字段(如金额、状态、ID),不验证随机值(如时间戳、流水号);
- 异常场景要反向断言:比如 “参数错误时,断言返回 400 而非 200”,覆盖负面用例;
- 避免硬编码敏感值:用变量代替固定值(如
pm.environment.get("city")),适配多环境测试; - 断言名称要清晰:比如 “响应码为 200”“客户 ID 和入参一致”,方便失败时快速定位问题。
五、实战示例(银行风险评估接口全套断言)
javascript
运行
// 1. 基础断言
pm.test("响应码200", () => pm.response.to.have.status(200));
pm.test("响应为JSON格式", () => pm.response.to.be.json);
// 2. 业务断言
const res = pm.response.json();
pm.test("业务成功(code=0)", () => pm.expect(res.code).to.eql(0));
pm.test("包含客户ID字段", () => pm.expect(res.data).to.have.property("customer_id"));
pm.test("风险等级为高/中/低", () => {
const riskLevels = ["高", "中", "低"];
pm.expect(riskLevels).to.include(res.data.risk_level);
});
// 3. 数据一致性断言
pm.test("客户ID和入参一致", () => {
const reqId = pm.request.url.query.get("customer_id");
pm.expect(res.data.customer_id).to.eql(reqId);
});
// 4. 性能断言(可选)
pm.test("响应时间<1秒", () => pm.expect(pm.response.responseTime).to.be.below(1000));
按这个清单加断言,既能覆盖核心场景,又不会冗余,新手可以先从 “状态码 + 业务成功 + 核心字段” 这 3 个基础维度入手,再逐步补充其他维度。
mysql
第一阶段:基础核心语法(09:00-11:00,2 小时,银行基础操作必备)
1. 数据库 / 表基础操作(高频★★★★★)
银行项目需频繁切换库、查看表结构,这是最基础且每天必用的操作
sql
-- 1. 切换指定数据库(银行项目多库隔离:客户库、账务库、流水库)
USE 银行客户数据库名;
-- 2. 查看当前库下所有表
SHOW TABLES;
-- 3. 查看表结构(必用!确认字段类型:金额decimal/手机号varchar/日期datetime)
DESC 客户表; -- 简写,等价于 DESCRIBE 客户表;
2. 单表查询 SELECT(高频★★★★★,银行 80% 操作是查询)
✅ 基础语法(核心中的核心,所有银行数据提取的基础)
sql
-- 语法模板
SELECT [字段1,字段2,.../*] -- *代表查询所有字段,生产环境尽量写具体字段(效率高)
FROM 表名
[WHERE 筛选条件] -- 按条件过滤数据(核心)
[ORDER BY 字段 ASC/DESC] -- 排序:ASC升序(默认)、DESC降序(金额/时间常用)
[LIMIT 起始行, 查询行数]; -- 分页(银行导出报表、分页展示必备)
✅ 银行高频筛选条件运算符(背熟,90% 银行查询会用到)
- 等值 / 不等值:
=(等于)、!=/<>(不等于)→ 查指定客户、指定卡号数据 - 范围:
>、<、>=、<=→ 查「余额≥50 万」的 VIP 客户、「近 30 天」流水 - 模糊匹配:
LIKE→%匹配任意字符、_匹配单个字符 → 查「手机号以 138 开头」「姓名含 “丽”」的客户 - 空值判断:
IS NULL(为空)、IS NOT NULL(不为空)→ 查「未预留手机号」的客户 - 多条件组合:
AND(且)、OR(或)、NOT(非)→ 核心组合,高频度 100%
3. 增删改语句(高频★★★★,银行账务录入 / 客户信息更新必备)
❗ 银行项目警示:DELETE/UPDATE 必须加 WHERE 条件,否则会清空整张表 / 更新所有数据,属于生产重大事故!
sql
-- 1. 新增数据(INSERT,客户开户、账务入账)
INSERT INTO 表名(字段1,字段2,字段3) VALUES(值1,值2,值3);
-- 2. 更新数据(UPDATE,客户手机号/地址修改、账户余额更新)
UPDATE 表名 SET 字段1=新值,字段2=新值 WHERE 筛选条件; -- 必须加WHERE!
-- 3. 删除数据(DELETE,销户操作)
DELETE FROM 表名 WHERE 筛选条件; -- 必须加WHERE!
第二阶段:进阶核心语法(11:00-14:00,3 小时含午休,银行统计 / 对账必备)
此阶段是银行项目分水岭,80% 的银行 SQL 需求(统计报表、对账、数据汇总)均依赖这些语法,必须吃透 + 大量练习!
✅ 必学知识点(按银行高频度排序,优先级从高到低)
1. 聚合函数(高频★★★★★,银行统计核心,无死角掌握)
✅ 5 个核心聚合函数(银行报表 100% 用到,背熟用法),搭配 AS 给结果起别名(报表必备)
sql
COUNT(*) -- 统计行数 → 统计客户数、交易笔数
SUM(字段) -- 求和 → 统计总交易金额、总存款余额
AVG(字段) -- 平均值 → 统计客户平均余额、平均交易金额
MAX(字段) -- 最大值 → 最大单笔交易、最高账户余额
MIN(字段) -- 最小值 → 最小单笔存款、最低账户余额
✅ 银行高频示例:
sql
-- 统计所有成功交易的总金额,别名「总交易金额」
SELECT SUM(trans_amount) AS 总交易金额 FROM t_transaction WHERE trans_status='成功';
-- 统计储蓄卡账户的平均余额
SELECT AVG(balance) AS 储蓄卡平均余额 FROM t_account WHERE acc_type='储蓄卡';
2. 分组查询 GROUP BY + 分组筛选 HAVING(高频★★★★★,银行核心统计)
✅ 核心逻辑:先分组,再统计;先 WHERE 筛选行,再 HAVING 筛选分组结果✅ 语法模板(银行必背):
sql
SELECT 分组字段, 聚合函数(统计字段) AS 别名
FROM 表名
WHERE 行筛选条件 -- 筛选单条数据,执行在分组前
GROUP BY 分组字段 -- 按指定字段分组(客户类型、账户类型、交易类型)
HAVING 分组筛选条件; -- 筛选分组结果,必须搭配聚合函数,执行在分组后
✅ 银行高频示例:
sql
-- 按交易类型分组,统计每种交易的总金额,且只显示总金额≥100万的分组
SELECT trans_type, SUM(trans_amount) AS 交易总金额
FROM t_transaction
WHERE trans_status='成功'
GROUP BY trans_type
HAVING SUM(trans_amount) >= 1000000;
3. 多表连接查询(高频★★★★★,银行对账 / 关联查询核心)
银行数据均为关联存储(客户→账户→流水),多表连接是项目中最常用的高级语法,3 种核心连接必须吃透:
sql
-- 1. INNER JOIN 内连接 → 只查「两张表都匹配」的数据(对账核心,最常用)
SELECT 字段 FROM 表1 INNER JOIN 表2 ON 表1.关联字段 = 表2.关联字段;
-- 2. LEFT JOIN 左连接 → 查「左表所有数据 + 右表匹配数据」(客户-账户关联,必用)
SELECT 字段 FROM 表1 LEFT JOIN 表2 ON 表1.关联字段 = 表2.关联字段;
-- 3. RIGHT JOIN 右连接 → 查「右表所有数据 + 左表匹配数据」(流水-账户关联)
SELECT 字段 FROM 表1 RIGHT JOIN 表2 ON 表1.关联字段 = 表2.关联字段;
✅ 银行核心示例(对账场景):
sql
-- 关联3张表,查询「VIP客户」的姓名、银行卡号、近30天交易金额,按交易金额降序
SELECT c.cust_name, a.acc_no, t.trans_amount
FROM t_customer c
INNER JOIN t_account a ON c.cust_id = a.cust_id
INNER JOIN t_transaction t ON a.acc_id = t.acc_id
WHERE c.cust_type='VIP' AND t.trans_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
ORDER BY t.trans_amount DESC;
4. 子查询(高频★★★★,银行复杂条件筛选核心)
✅ 定义:查询中嵌套查询,内层查询结果作为外层查询的「条件 / 数据源」,解决银行复杂筛选需求(如:查「余额高于平均余额」的客户)✅ 2 种常用形式(银行必用):
sql
-- 形式1:子查询作为WHERE条件(用IN/=/>/<等运算符)
SELECT * FROM 表1 WHERE 字段 IN (SELECT 字段 FROM 表2 WHERE 条件);
-- 形式2:子查询作为临时表(FROM后,需起别名)
SELECT * FROM (SELECT 字段 FROM 表1 WHERE 条件) AS 临时表名 WHERE 条件;
✅ 银行高频示例:
sql
-- 查询余额高于「所有账户平均余额」的储蓄卡账户(子查询求平均余额)
SELECT acc_no, balance FROM t_account
WHERE acc_type='储蓄卡' AND balance > (SELECT AVG(balance) FROM t_account);
第三阶段:高级实战语法 + 银行项目综合刷题(14:00-17:00,3 小时,学完直接落地)
此阶段是银行项目拔高内容,覆盖复杂统计、性能优化、特殊场景处理,学完即可独立完成银行项目中 99% 的 SQL 需求,配套 10 道综合大题(银行真实场景复刻)。
✅ 必学高级知识点(银行项目高频难点,直击痛点)
1. 分页查询优化(高频★★★★★,银行报表 / 分页展示必备)
银行数据量极大(千万级流水、百万级客户),LIMIT 基础分页效率低,银行最优分页写法(基于主键自增):
sql
-- 低效写法(大数据量卡顿)
SELECT * FROM t_transaction LIMIT 10000, 10; -- 跳过1万行,查10行
-- 高效写法(银行生产环境必用,主键过滤)
SELECT * FROM t_transaction WHERE trans_id > 10000 LIMIT 10;
2. 日期函数(高频★★★★★,银行时间筛选核心)
银行所有数据均需按时间筛选(日 / 周 / 月 / 季 / 年报表),背熟以下 5 个核心日期函数:
sql
NOW() -- 获取当前时间(datetime)→ 2026-01-02 15:30:00
DATE(NOW()) -- 提取日期部分 → 2026-01-02
DATE_SUB(NOW(), INTERVAL 30 DAY) -- 30天前的时间(近30天流水)
YEAR/DATE/HOUR -- 提取年/日/小时 → YEAR(trans_time)=2025
DATEDIFF(日期1,日期2) -- 计算两个日期的天数差 → 客户开户天数
3. CASE WHEN 条件判断(高频★★★★,银行报表多维度统计)
✅ 核心作用:一行内实现多条件统计,银行报表必备(如:统计不同区间的客户数、不同金额的交易笔数)✅ 银行示例:
sql
-- 统计账户余额区间分布:0-1万、1-10万、10万以上
SELECT
COUNT(CASE WHEN balance<=10000 THEN 1 END) AS '0-1万',
COUNT(CASE WHEN balance>10000 AND balance<=100000 THEN 1 END) AS '1-10万',
COUNT(CASE WHEN balance>100000 THEN 1 END) AS '10万以上'
FROM t_account;
4. DISTINCT 去重(高频★★★★,银行数据去重)
✅ 核心作用:去除重复数据,银行场景:查询「有交易的唯一客户数」「唯一卡号数」
sql
-- 查询有过交易的唯一客户数
SELECT COUNT(DISTINCT c.cust_id) AS 交易客户数
FROM t_customer c JOIN t_account a ON c.cust_id=a.cust_id
JOIN t_transaction t ON a.acc_id=t.acc_id;
case
一、版本 1 ✅ 你的原 SQL「补全 ELSE」版(直接复制执行)
完美适配你的余额区间统计需求,手动加ELSE兜底,逻辑更严谨、结果更清晰,执行结果和原 SQL 一致,但可读性 / 健壮性翻倍:
sql
SELECT
-- 余额0-1万:满足条件返回1,不满足返回NULL
COUNT(CASE WHEN balance <= 10000 THEN 1 ELSE NULL END) AS '0-1万',
-- 余额1-10万:满足条件返回1,不满足返回NULL
COUNT(CASE WHEN balance > 10000 AND balance <= 100000 THEN 1 ELSE NULL END) AS '1-10万',
-- 余额10万以上:满足条件返回1,不满足返回NULL
COUNT(CASE WHEN balance > 100000 THEN 1 ELSE NULL END) AS '10万以上'
FROM t_account;
✅ 核心讲解:ELSE在这里的作用
- 你的原 SQL 没写
ELSE→ MySQL 默认返回NULL,和上面写ELSE NULL效果完全一样; - 手动加
ELSE NULL是「显式写法」,好处是:代码逻辑一目了然,团队协作时别人能立刻看懂你的判断规则,这是企业里的规范写法; - 配合
COUNT()使用:COUNT()只统计非 NULL 值,NULL会被直接忽略 → 刚好实现「符合条件就计数,不符合就不计」。
二、版本 2 ✅ CASE WHEN+ELSE完整语法版(企业级必用,拓展学习)
这是CASE WHEN的 完整标准写法,包含WHEN 多条件 + ELSE 兜底 + END,能应对更复杂的业务场景,也是工作中最常用的写法,建议重点掌握:
✅ 示例 1:余额统计(带 ELSE 兜底,分类无遗漏)
sql
SELECT
-- 完整CASE WHEN结构:多条件+ELSE兜底
COUNT(CASE
WHEN balance <= 10000 THEN 1
WHEN balance > 10000 AND balance <= 100000 THEN 1
WHEN balance > 100000 THEN 1
ELSE NULL -- 兜底:所有不满足上述条件的情况,统一返回NULL
END) AS '有效账户总数',
-- 单独统计:异常余额(比如负数、0)
COUNT(CASE WHEN balance <= 0 THEN 1 ELSE NULL END) AS '异常余额账户'
FROM t_account;
✅ 示例 2:拓展场景(账户类型 + 余额双条件,ELSE 实战)
结合你的银行表,写一个更贴近业务的案例,帮你举一反三:
sql
SELECT
-- 统计:储蓄卡不同余额区间数量
COUNT(CASE WHEN acc_type='储蓄卡' AND balance <=10000 THEN 1 ELSE NULL END) AS '储蓄卡_0-1万',
COUNT(CASE WHEN acc_type='储蓄卡' AND balance >100000 THEN 1 ELSE NULL END) AS '储蓄卡_10万以上',
-- 统计:信用卡/理财账户(ELSE合并兜底)
COUNT(CASE WHEN acc_type!='储蓄卡' THEN 1 ELSE NULL END) AS '其他账户总数'
FROM t_account;
🎯 必记!CASE WHEN完整语法规则(2 种写法,全覆盖)
✅ 写法 1:【搜索式 CASE】(最常用,你用的就是这种)
👉 适用场景:多条件判断、范围判断(比如区间、多字段组合条件),也是企业开发 99% 的场景用法
sql
CASE
WHEN 条件表达式1 THEN 返回值1
WHEN 条件表达式2 THEN 返回值2
WHEN 条件表达式3 THEN 返回值3
...
ELSE 兜底返回值 -- 可选,不写默认返回NULL
END
✅ 核心特点:WHEN后接完整条件表达式(可以用>、<、AND、OR、=等所有运算符),非常灵活。
✅ 写法 2:【简单式 CASE】(特殊场景用)
👉 适用场景:字段等于固定值的判断(比如性别、账户类型、客户等级),写法更简洁
sql
CASE 待判断字段名
WHEN 固定值1 THEN 返回值1
WHEN 固定值2 THEN 返回值2
WHEN 固定值3 THEN 返回值3
...
ELSE 兜底返回值 -- 可选,不写默认返回NULL
END
✅ 举个例子(统计不同账户类型数量):
sql
SELECT
COUNT(CASE acc_type WHEN '储蓄卡' THEN 1 ELSE NULL END) AS '储蓄卡',
COUNT(CASE acc_type WHEN '信用卡' THEN 1 ELSE NULL END) AS '信用卡',
COUNT(CASE acc_type WHEN '理财账户' THEN 1 ELSE NULL END) AS '理财账户',
COUNT(CASE acc_type ELSE 1 END) AS '未知账户' -- ELSE兜底
FROM t_account;
🎯 关键知识点总结(3 个核心,记牢不踩坑)
✅ 1. ELSE的核心价值(为什么一定要加?)
- ✔️ 兜底防遗漏:确保所有数据都能被判断,不会出现「无匹配结果」的情况;
- ✔️ 逻辑更严谨:明确「不满足条件时的返回值」,避免因 MySQL 默认
NULL导致的统计错误; - ✔️ 可读性更强:团队协作时,别人能一眼看懂你的完整判断规则。
✅ 2. CASE WHEN和COUNT()搭配的底层原理(必懂)
CASE WHEN满足条件 → 返回1(非 NULL 值),不满足 → 返回NULL;COUNT(字段/值)→ 只统计非 NULL 值的数量,自动忽略NULL;- ✅ 两者搭配 → 完美实现「符合条件就计数,不符合就跳过」,这是 SQL 区间统计的经典写法!
✅ 3. 语法铁律(绝对不能错)
CASE开头,必须以END结尾(少一个都报错!);ELSE是可选的,不写则默认返回NULL;THEN后只能跟「单个值」(数字 / 字符串 / NULL),不能写复杂语句;CASE WHEN可以嵌套、可以和任何聚合函数(COUNT/SUM/AVG)搭配。
✅ 额外福利:3 个企业级高频实战案例(直接套用)
基于你的银行表,再给 3 个工作中常用的CASE WHEN+ELSE案例,练完直接上手项目:
案例 1:统计客户等级 + 账户余额(双维度)
sql
SELECT
c.cust_type AS '客户等级',
COUNT(CASE WHEN a.balance>0 THEN 1 ELSE NULL END) AS '有余额账户数',
SUM(CASE WHEN a.balance>0 THEN a.balance ELSE 0 END) AS '总余额'
FROM t_customer c
JOIN t_account a ON c.cust_id=a.cust_id
GROUP BY c.cust_type;
案例 2:交易状态分类统计(ELSE 合并异常)
sql
SELECT
COUNT(CASE WHEN trans_status='成功' THEN 1 ELSE NULL END) AS '成功交易',
COUNT(CASE WHEN trans_status='失败' THEN 1 ELSE NULL END) AS '失败交易',
COUNT(CASE ELSE 1 END) AS '其他状态交易' -- ELSE兜底所有剩余情况
FROM t_transaction;
案例 3:余额分级打标签(ELSE 统一标为「普通」)
sql
SELECT
acc_no AS '银行卡号',
balance AS '账户余额',
-- CASE WHEN打标签,ELSE兜底
CASE
WHEN balance >= 500000 THEN '高净值账户'
WHEN balance >=100000 THEN '优质账户'
WHEN balance >=10000 THEN '普通账户'
ELSE '小额账户' -- 所有不满足的,统一标为小额
END AS '账户等级标签'
FROM t_account;
✨ 最终总结
- 你的原 SQL ✅ 本质是
CASE WHEN的「简化写法」,省略ELSE默认返回NULL; - 工作中 ✅ 建议显式写
ELSE,逻辑更严谨,是团队规范; CASE WHEN核心搭配 ✅COUNT/SUM/AVG做条件统计,是 SQL 面试 / 工作必考的知识点;- 记住 2 种写法 ✅ 「搜索式」(范围判断)+「简单式」(等值判断),覆盖所有场景。
以上所有 SQL 都能直接复制到你的 Navicat 执行,放心用~ 😊
limit 用法
✅ MySQL LIMIT 用法 超全详解(结合你的 SQL + 实操案例,一看就会)
✅ 先给你最核心的结论(对应你的 SQL)
你的语句里 LIMIT 10,10 → ✔️ 跳过前 10 条结果,只获取后续的 10 条数据,是 MySQL 分页查询的核心写法,也是工作中最常用的格式!结合你的业务:查询 2025 年 12 月私行客户理财交易、按交易时间倒序后,取第 11~20 条数据(最新的前 10 条跳过,拿下一批 10 条)。
一、LIMIT 完整语法(2 种写法,全部掌握)
LIMIT 是 MySQL 专属的结果集行数限制关键字,作用就是「控制查询结果返回多少行、从哪一行开始返回」,无兼容性问题,所有 MySQL 版本通用,分 2 种写法:
✅ 写法 1:LIMIT 跳过行数, 读取行数(你的 SQL 用的这种,分页专用)
sql
# 语法格式
SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT M, N;
✅ 含义拆解:
-
M:要跳过的行数(从 0 开始计数,第一行是 0、第二行是 1...); -
N:要读取的行数(最终返回给你的数据条数);✅ 你的案例对应:
LIMIT 10,10→ M=10,N=10 → 跳过前 10 行,读 10 行 → 结果就是第 11~20 条。
✅ 写法 2:LIMIT 读取行数(最简写法,取前 N 条)
sql
# 语法格式
SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT N;
✅ 含义:直接返回排序后的前 N 条数据,等价于 LIMIT 0, N;✅ 实操示例(适配你的业务):
sql
-- 取私行客户12月理财交易,最新的前10条(常用!)
SELECT c.cust_name, a.acc_no, t.trans_amount, t.trans_time
FROM t_customer c JOIN t_account a ON c.cust_id=a.cust_id
JOIN t_transaction t ON a.acc_id=t.acc_id
WHERE c.cust_type='私行' AND t.trans_type='理财'
AND YEAR(t.trans_time)=2025 AND MONTH(t.trans_time)=12
ORDER BY t.trans_time DESC LIMIT 10;
二、✅ 分页查询核心规律(必背!工作 100% 用得上)
LIMIT M,N 是分页功能的底层实现,比如前端页面「每页显示 10 条,点第 1 页 / 第 2 页 / 第 3 页」,本质就是改 M 的值,规律超简单:
✅ 公式:
LIMIT (页码-1)*每页条数 , 每页条数
结合你的案例(每页 10 条):
- 第 1 页:
LIMIT 0,10→ 跳过 0 条,读 10 条 → 1~10 条 - 第 2 页:
LIMIT 10,10→ 跳过 10 条,读 10 条 →11~20 条 - 第 3 页:
LIMIT 20,10→ 跳过 20 条,读 10 条 →21~30 条 - 第 N 页:
LIMIT (N-1)*10,10
✅ 拓展:如果你的需求是「每页 20 条,查第 5 页」,直接套公式:LIMIT (5-1)*20,20 → LIMIT 80,20。
三、✅ 关键注意事项(避坑必备,3 个核心)
✅ 1. LIMIT 必须写在 SQL 语句的最后面
语法铁律,顺序不能乱!正确执行顺序:SELECT → FROM → JOIN → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT你的语句顺序是完美的 ✔️,严格遵守了这个规则,这是LIMIT生效的前提!
✅ 2. LIMIT 生效前,会先执行 ORDER BY 排序
✅ 核心逻辑:先排序、再分页,这是分页的意义!你的语句先执行 ORDER BY t.trans_time DESC(交易时间倒序,最新的在前),再执行 LIMIT 10,10,拿到的就是「最新的第 11~20 条」;如果不排序直接用LIMIT,返回的结果是随机的,毫无意义 ❌。
✅ 3. 跳过行数 M 可以为 0,不能为负数
LIMIT 0,10✔️ 合法,等价于LIMIT 10;LIMIT -5,10❌ 报错,MySQL 不支持负数的跳过行数。
四、✅ 进阶用法(MySQL8.0+ 推荐,更易读)
MySQL8.0 及以上版本,支持 LIMIT N OFFSET M 写法,和 LIMIT M,N 完全等价,只是换了个顺序,可读性更强(一眼能看出「取 N 条、跳过 M 条」):
sql
# 两种写法 结果完全一致
LIMIT 10,10;
LIMIT 10 OFFSET 10; -- 推荐:取10条,跳过10条
✅ 适配你的 SQL 的写法:
sql
SELECT c.cust_name, a.acc_no, t.trans_amount, t.trans_time
FROM t_customer c JOIN t_account a ON c.cust_id=a.cust_id
JOIN t_transaction t ON a.acc_id=t.acc_id
WHERE c.cust_type='私行' AND t.trans_type='理财'
AND YEAR(t.trans_time)=2025 AND MONTH(t.trans_time)=12
ORDER BY t.trans_time DESC LIMIT 10 OFFSET 10;
五、✅ 3 个实战案例(直接复制执行,练会为止)
✅ 案例 1:基础用法 → 取储蓄卡余额最高的前 5 个账户
sql
SELECT acc_no, balance
FROM t_account
WHERE acc_type='储蓄卡'
ORDER BY balance DESC
LIMIT 5; -- 直接取前5条
✅ 案例 2:分页用法 → 取客户姓名按 A-Z 排序,第 3 页(每页 8 条)
sql
SELECT cust_id, cust_name
FROM t_customer
ORDER BY cust_name ASC
LIMIT 16,8; -- (3-1)*8=16 → 跳过16条,取8条
✅ 案例 3:结合业务 → 取 2025 年 12 月交易金额 > 10 万的前 3 条理财交易
sql
SELECT c.cust_name, t.trans_amount, t.trans_time
FROM t_customer c
JOIN t_account a ON c.cust_id=a.cust_id
JOIN t_transaction t ON a.acc_id=t.acc_id
WHERE t.trans_type='理财' AND t.trans_amount>100000
AND YEAR(t.trans_time)=2025 AND MONTH(t.trans_time)=12
ORDER BY t.trans_amount DESC
LIMIT 3; -- 取金额最高的前3条
✨ 最终总结(30 秒记牢所有核心)
LIMIT N→ 取排序后的前 N 条,最常用、最简写法;LIMIT M,N→ 跳过 M 条,取 N 条,分页专用,公式:(页码-1)*每页条数, 每页条数;LIMIT N OFFSET M→ MySQL8.0 + 推荐,和LIMIT M,N等价,可读性更强;- 铁律:
LIMIT必须写在 SQL最后,且必须配合ORDER BY使用才有意义。
浙公网安备 33010602011771号