ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

零基础学SQL 04:WHERE条件总写错?AND/OR/IN一图搞懂

2026/8/14 15:23:52 拓冰建站 浏览量
零基础学SQL 04:WHERE条件总写错?AND/OR/IN一图搞懂

先说点真话

当年做数据分析项目那会儿,有回要给领导出一张"技术部 + 销售部里,工资超过 9000 的人"的名单。新人交上来的 SQL 长这样:

WHERE部门='技术部'OR部门='销售部'AND工资>9000

结果查出来技术部所有人(含工资 8000 的)全在里头——因为AND优先级高于OR,上面那句实际等于"技术部全部,或者(销售部且工资>9000)"。上报的数字直接错了,挨了一顿批。

这事儿让我记住:WHERE不只会写单个条件,条件一多,优先级和写法就是坑。今天把AND/ORINBETWEENLIKE一次讲透,你写报表、做筛选再也不会被自己坑。

💡 「SQL 从入门到精通」系列持续更新中,关注我不迷路,每篇都是实战干货。


一、AND / OR:多条件组合,先搞清优先级

你会什么场景下用到它?
你想同时卡好几个条件,比如"技术部且工资>9000"“北京或上海的客户”。这时候就要用AND(并且)和OR(或者)把条件拼起来。

关键点:ANDOR优先级高。就像乘法比加法先算一样。想改变顺序,必须加括号()

正确写法(加括号才是你真正想要的):

-- 意图:只要"技术部或销售部"里,工资>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工资BETWEEN8000AND9500;

两个要点:

  • 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 个坑(重点看)

  1. AND/OR 不加括号,统计口径错
    上面那个"技术部或销售部且>9000"的例子,少一对括号,上报数字全错。结论:多条件必加括号,别赌默认优先级。

  2. 以为 BETWEEN 不含边界
    漏算临界值,报表人数差几个。结论:BETWEEN闭区间,两头都算。

  3. LIKE 前导通配符拖垮大表查询
    '%x%'让几千万行表全表扫描、查询超时。结论:模糊查询尽量写成'x%',别在前面加%


六、3 个练习(自己跑一遍)

基于下面的员工表订单表

  1. 查出工资在 9000 到 9500 之间的员工姓名和工资。
  2. 查出部门是技术部或销售部,且工资大于 9000 的员工。
  3. 用 LIKE 查出姓名以"王"开头的员工。

参考答案(先自己写,再对照):

-- 1SELECT姓名,工资FROM员工表WHERE工资BETWEEN9000AND9500;-- 2(括号决定优先级)SELECT姓名,部门,工资FROM员工表WHERE(部门='技术部'OR部门='销售部')AND工资>9000;-- 3SELECT姓名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 张固定表。每张表先DROPCREATE,所以每读一篇文重新跑一次这个块都安全,不用从新建表。

DROPTABLEIFEXISTS员工表;CREATETABLE员工表(员工idINTPRIMARYKEY,姓名VARCHAR(20),部门VARCHAR(20),工资DECIMAL(10,2),邮箱VARCHAR(50),手机VARCHAR(20),入职日期DATE);INSERTINTO员工表(员工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');DROPTABLEIFEXISTS订单表;CREATETABLE订单表(订单idINTPRIMARYKEY,员工idINT,订单金额DECIMAL(10,2),下单时间DATETIME,付款时间DATETIME,状态VARCHAR(20));INSERTINTO订单表(订单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,'待付款');DROPTABLEIFEXISTS用户表;CREATETABLE用户表(用户idINTPRIMARYKEY,姓名VARCHAR(20),手机VARCHAR(20),邮箱VARCHAR(50),地址VARCHAR(100));INSERTINTO用户表(用户id,姓名,手机,邮箱,地址)VALUES(1,'张三','13900000001','zhangsan@demo.com','北京市朝阳区'),(2,'李四','13900000002','lisi@demo.com','上海市浦东新区'),(3,'王五','13900000003','wangwu@demo.com','广州市天河区');DROPTABLEIFEXISTS任务表;CREATETABLE任务表(任务idINTPRIMARYKEY,员工idINT,备注VARCHAR(100),状态VARCHAR(20));INSERTINTO任务表(任务id,员工id,备注,状态)VALUES(1,1,'完成需求评审','已完成'),(2,2,NULL,'进行中'),(3,3,'修复线上bug','已完成'),(4,4,NULL,'待分配');