先说点真话
当年做数据分析项目那会儿,有回要给领导出一张"技术部 + 销售部里,工资超过 9000 的人"的名单。新人交上来的 SQL 长这样:
WHERE 部门='技术部' OR 部门='销售部' AND 工资>9000
结果查出来技术部所有人(含工资 8000 的)全在里头——因为 AND 优先级高于 OR,上面那句实际等于"技术部全部,或者(销售部且工资>9000)"。上报的数字直接错了,挨了一顿批。
这事儿让我记住:WHERE 不只会写单个条件,条件一多,优先级和写法就是坑。今天把 AND/OR、IN、BETWEEN、LIKE 一次讲透,你写报表、做筛选再也不会被自己坑。
💡 「SQL 从入门到精通」系列持续更新中,关注我不迷路,每篇都是实战干货。
一、AND / OR:多条件组合,先搞清优先级
你会什么场景下用到它? 你想同时卡好几个条件,比如"技术部且工资>9000"“北京或上海的客户”。这时候就要用 AND(并且)和 OR(或者)把条件拼起来。
关键点:AND 比 OR 优先级高。 就像乘法比加法先算一样。想改变顺序,必须加括号 ()。
正确写法(加括号才是你真正想要的):
— 意图:只要"技术部或销售部"里,工资>9000 的人
SELECT 姓名, 部门, 工资
FROM 员工表
WHERE (部门='技术部' OR 部门='销售部') AND 工资 > 9000;
结果(技术部 9000 不达标被排除,销售部 9200 两人达标):
| 王五 | 销售部 | 9200 |
| 赵六 | 销售部 | 9200 |
最大的坑: 不加括号时,数据库按"先 AND 后 OR"算。下面这句和上面那句意思完全不同:
— ❌ 实际含义:技术部全部,或(销售部且工资>9000)
WHERE 部门='技术部' OR 部门='销售部' AND 工资 > 9000
记住口诀:条件一多,先想清楚"我要的是哪一组",然后用括号把那组括起来。宁可多写括号,别信默认优先级。
二、IN:替代一长串 OR,清爽又高效
你会什么场景下用到它? 你想筛"部门是技术部或销售部或市场部",用 OR 要写三遍 部门=,又长又难看:
— 啰嗦写法
WHERE 部门='技术部' OR 部门='销售部' OR 部门='市场部'
正确写法:用 IN 一把梭
SELECT 姓名, 部门
FROM 员工表
WHERE 部门 IN ('技术部', '销售部', '市场部');
IN 后面跟一个值列表,等于"等于其中任意一个"。可读性高,数据库也更容易优化。你后面学子查询时,IN (SELECT …) 还能接一整张结果表,非常常用。
三、BETWEEN:闭区间范围筛选
你会什么场景下用到它? 你想筛"工资在 8000 到 9500 之间",包括 8000 和 9500 两端。
正确写法:
SELECT 姓名, 工资
FROM 员工表
WHERE 工资 BETWEEN 8000 AND 9500;
两个要点:
- BETWEEN 是闭区间,包含两端(8000 和 9500 都算)。
- 等价于 工资 >= 8000 AND 工资 <= 9500,但 BETWEEN 写起来更短,语义更清楚。
我当年踩的坑: 有人以为 BETWEEN 不含边界,少算了临界值,报表差了那么几个人。所以记住——BETWEEN 两头都算。
四、LIKE:模糊查询,找"长得像"的数据
你会什么场景下用到它? 你记不全准确名字,只想找"姓张的"“名字里带’小’的”“邮箱是 demo 结尾的”。精确等号 = 匹配不了,就要用 LIKE 做模糊匹配。
两个通配符:
- %:代表任意长度(0 个、1 个、多个字符)
- _:代表恰好 1 个字符
正确写法:
— 姓"张"的(张开头,后面任意)
SELECT 姓名 FROM 员工表 WHERE 姓名 LIKE '张%';
— 名字里带"小"的(小在任意位置)
SELECT 姓名 FROM 用户表 WHERE 姓名 LIKE '%小%';
— 邮箱是 demo.com 结尾的
SELECT 邮箱 FROM 用户表 WHERE 邮箱 LIKE '%demo.com';
— 姓名恰好 2 个字、且姓张(_ 占一个位置)
SELECT 姓名 FROM 员工表 WHERE 姓名 LIKE '张_';
我当年踩的坑(性能): 在一张几千万行的大表里写 LIKE '%关键字%'(前面带 %),数据库没法用索引,只能全表逐行扫,查询直接超时。结论:LIKE 的通配符放前面(前导通配)会拖慢查询,大表能避免就避免,非要搜就尽量写成 '关键字%'(后缀匹配,能用索引)。
五、当年我踩过的 3 个坑(重点看)
AND/OR 不加括号,统计口径错 上面那个"技术部或销售部且>9000"的例子,少一对括号,上报数字全错。结论:多条件必加括号,别赌默认优先级。
以为 BETWEEN 不含边界 漏算临界值,报表人数差几个。结论:BETWEEN 闭区间,两头都算。
LIKE 前导通配符拖垮大表查询 '%x%' 让几千万行表全表扫描、查询超时。结论:模糊查询尽量写成 'x%',别在前面加 %。
六、3 个练习(自己跑一遍)
基于下面的 员工表 和 订单表:
参考答案(先自己写,再对照):
— 1
SELECT 姓名, 工资 FROM 员工表 WHERE 工资 BETWEEN 9000 AND 9500;
— 2(括号决定优先级)
SELECT 姓名, 部门, 工资
FROM 员工表
WHERE (部门='技术部' OR 部门='销售部') AND 工资 > 9000;
— 3
SELECT 姓名 FROM 员工表 WHERE 姓名 LIKE '王%';
思考题:练习 2 如果不加括号,结果会变成什么?为什么技术部工资 9000 的人会被算进来?想明白这个,AND/OR 优先级这关就过了。
七、小结
- AND(并且)/ OR(或者)组合条件,AND 优先级高于 OR,多条件必加括号。
- IN (值1, 值2, …) 替代一长串 OR,清爽高效,后面还能接子查询。
- BETWEEN A AND B 是闭区间,包含 A 和 B 两端。
- LIKE 模糊匹配:% 任意长度、_ 恰好一个;前导通配 %x% 会拖慢大表查询,尽量写成 x%。
互动时间(站队投票):你写 WHERE 时最常被哪块坑过?我当年铁定选"AND/OR 不加括号,然后对着错数字发呆"。是 ① AND/OR 优先级、② BETWEEN 边界、还是 ③ LIKE 慢查询?评论区打 1/2/3,我挑典型的下篇专门讲索引优化避坑 😂
👋 我是 Hello_world12131,十年数据分析经验。 这篇有用的话 点个赞 + 收藏,顺便 关注我 📌,SQL 从入门到精通系列每周更新,关注后不错过新篇。 📎 系列目录(置顶) | 🔗 相关推荐: 篇02 SELECT/FROM/WHERE 篇03 ORDER BY/GROUP BY/HAVING SQL 函数速查表 | ⏭️ 下篇预告:篇05 去重与分页 DISTINCT/LIMIT
📋 SQL 系列统一练习表(复制即可运行,可重复执行,不会报"表已存在")
本系列所有文章都基于下面这 4 张固定表。每张表先 DROP 再 CREATE,所以每读一篇文重新跑一次这个块都安全,不用从新建表。
DROP TABLE IF EXISTS 员工表;
CREATE TABLE 员工表 (
员工id INT PRIMARY KEY,
姓名 VARCHAR(20),
部门 VARCHAR(20),
工资 DECIMAL(10,2),
邮箱 VARCHAR(50),
手机 VARCHAR(20),
入职日期 DATE
);
INSERT INTO 员工表 (员工id, 姓名, 部门, 工资, 邮箱, 手机, 入职日期) VALUES
(1, '张三', '技术部', 9000.00, 'zhangsan@demo.com', '13800000001', '2019-03-01'),
(2, '李四', '技术部', 9000.00, 'lisi@demo.com', '13800000002', '2020-07-15'),
(3, '王五', '销售部', 9200.00, 'wangwu@demo.com', '13800000003', '2018-01-10'),
(4, '赵六', '销售部', 9200.00, 'zhaoliu@demo.com', '13800000004', '2021-05-20');
DROP TABLE IF EXISTS 订单表;
CREATE TABLE 订单表 (
订单id INT PRIMARY KEY,
员工id INT,
订单金额 DECIMAL(10,2),
下单时间 DATETIME,
付款时间 DATETIME,
状态 VARCHAR(20)
);
INSERT INTO 订单表 (订单id, 员工id, 订单金额, 下单时间, 付款时间, 状态) VALUES
(101, 1, 3000.00, '2026-01-10 10:00:00', '2026-01-10 10:05:00', '已付款'),
(102, 1, 2500.00, '2026-02-15 14:00:00', '2026-02-15 14:10:00', '已付款'),
(103, 3, 4000.00, '2026-03-20 09:30:00', '2026-03-20 09:40:00', '已付款'),
(104, 2, 1500.00, '2026-04-05 16:00:00', NULL, '待付款');
DROP TABLE IF EXISTS 用户表;
CREATE TABLE 用户表 (
用户id INT PRIMARY KEY,
姓名 VARCHAR(20),
手机 VARCHAR(20),
邮箱 VARCHAR(50),
地址 VARCHAR(100)
);
INSERT INTO 用户表 (用户id, 姓名, 手机, 邮箱, 地址) VALUES
(1, '张三', '13900000001', 'zhangsan@demo.com', '北京市朝阳区'),
(2, '李四', '13900000002', 'lisi@demo.com', '上海市浦东新区'),
(3, '王五', '13900000003', 'wangwu@demo.com', '广州市天河区');
DROP TABLE IF EXISTS 任务表;
CREATE TABLE 任务表 (
任务id INT PRIMARY KEY,
员工id INT,
备注 VARCHAR(100),
状态 VARCHAR(20)
);
INSERT INTO 任务表 (任务id, 员工id, 备注, 状态) VALUES
(1, 1, '完成需求评审', '已完成'),
(2, 2, NULL, '进行中'),
(3, 3, '修复线上bug', '已完成'),
(4, 4, NULL, '待分配');
网硕互联帮助中心



评论前必须登录!
注册