2.17 sql条件筛选(WHERE、比较运算符、逻辑运算符、BETWEEN、IN、LIKE模糊查询、IS NULL)
2.17 条件筛选(WHERE、比较运算符、逻辑运算符、BETWEEN、IN、LIKE模糊查询、IS NULL)
在电商数据分析中,你几乎不会查全表数据,永远是在筛选特定范围:
只看某天的订单。
只看金额大于500的高价值订单。
只看某个店铺或某个类目的商品。
只看已支付未发货的订单。
WHERE子句就是用来做条件筛选的。这一章我会带你彻底搞懂WHERE的各种用法:比较运算符、逻辑运算符、BETWEEN、IN、LIKE模糊查询、空值判断。学完之后,你能精准地从百万行数据中秒级提取你需要的行。
学习前准备:
已完成MySQL安装(参考系列前几章)
已安装DBeaver或Navicat
准备一个练习数据库,比如
where_demo
学习前环境准备
步骤1:确保MySQL服务已启动。
步骤2:创建练习数据库和表,并插入示例数据。
CREATEDATABASEwhere_demoCHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;USEwhere_demo;-- 订单表CREATETABLEorders(order_idVARCHAR(50)PRIMARYKEY,user_idINTNOTNULL,shop_nameVARCHAR(50)NOTNULL,amountDECIMAL(10,2)NOTNULL,order_statusVARCHAR(20)NOTNULL,create_timeDATETIMENOTNULL,product_nameVARCHAR(100));INSERTINTOordersVALUES('ORD001',1001,'女装旗舰店',299.00,'已支付','2025-06-01 10:00:00','碎花连衣裙'),('ORD002',1002,'女装旗舰店',189.00,'已取消','2025-06-01 11:00:00','纯棉T恤'),('ORD003',1003,'男装专营店',599.00,'已支付','2025-06-02 09:30:00','牛仔裤'),('ORD004',1001,'女装旗舰店',399.00,'已支付','2025-06-03 14:20:00','雪纺衫'),('ORD005',1004,'童装店',99.00,'已完成','2025-06-03 16:00:00','儿童T恤'),('ORD006',1005,'女装旗舰店',1299.00,'已支付','2025-06-04 08:30:00','真丝连衣裙'),('ORD007',1002,'男装专营店',89.00,'已取消','2025-06-04 10:00:00','休闲短裤'),('ORD008',1006,'女装旗舰店',89.00,'已支付','2025-06-05 09:00:00',NULL),('ORD009',1007,'男装专营店',259.00,'已支付','2025-06-05 14:00:00','Polo衫');WHERE条件筛选基础认知
WHERE子句用于过滤行,只保留满足条件的记录。它紧跟在FROM之后,在GROUP BY之前执行。
基本语法:
SELECT列FROM表WHERE条件;SQL执行顺序回顾:
FROM:确定数据来源WHERE:按行筛选GROUP BY、HAVING、SELECT、ORDER BY、LIMIT
在电商数据分析中的核心用途:
时间范围筛选(某天、某月、某季度)。
数值区间筛选(金额大于500)。
状态筛选(已支付、待发货)。
文本匹配(店铺名称、商品名称)。
我的踩坑经历:我第一次写
WHERE时,把条件写成了WHERE amount > 500 AND order_status = '已支付',结果正确。但后来我写了一个WHERE order_status = '已支付' AND amount > 500,效果一样。但切记:字符串值必须用单引号,数字不用。
比较运算符
4.1 基础语法
| 运算符 | 含义 |
|---|---|
= | 等于 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
<>或!= | 不等于 |
4.2 电商实操案例
案例一:查询金额大于500元的订单
SELECT*FROMordersWHEREamount>500;预期结果:ORD003(599)、ORD006(1299)。
案例二:查询金额小于100元的订单
SELECT*FROMordersWHEREamount<100;预期结果:ORD005(99)、ORD007(89)、ORD008(89)。
案例三:查询女装旗舰店的订单
SELECT*FROMordersWHEREshop_name='女装旗舰店';预期结果:ORD001、ORD002、ORD004、ORD006、ORD008。
案例四:查询不是“已支付”的订单
SELECT*FROMordersWHEREorder_status<>'已支付';-- 或 WHERE order_status != '已支付';预期结果:ORD002(已取消)、ORD005(已完成)、ORD007(已取消)。
4.3 分步操作
先确定要查询的表和列。
写出不带
WHERE的查询,看全量数据。加上
WHERE和比较条件。执行并验证结果行数。
避坑提醒:=比较时,字符串要精确匹配(大小写和空格)。MySQL默认不区分大小写,但区分末尾空格。比如'女装旗舰店 '(多一个空格)匹配不到。
实操避坑提醒:金额比较时,确保
amount列是数值类型,不能是带货币符号的字符串。否则比较结果可能错误。
逻辑运算符(AND、OR、NOT)
5.1 基础语法
AND:所有条件必须同时满足。OR:至少满足一个条件。NOT:取反。
5.2 电商实操案例
案例一:女装旗舰店且金额大于300元的订单
SELECT*FROMordersWHEREshop_name='女装旗舰店'ANDamount>300;预期结果:ORD004(399)、ORD006(1299)。
案例二:女装旗舰店或男装专营店的订单
SELECT*FROMordersWHEREshop_name='女装旗舰店'ORshop_name='男装专营店';预期结果:除童装店以外的所有订单(ORD001-004,006-009)。
案例三:金额大于500且状态为“已支付”,或者金额小于100且状态为“已支付”
SELECT*FROMordersWHERE(amount>500ORamount<100)ANDorder_status='已支付';注意括号优先级:AND优先级高于OR,所以括号很重要。
预期结果:金额>500且已支付:ORD003(599)、ORD006(1299);金额<100且已支付:ORD008(89) → 共3条。
5.3 分步操作
先写单条件查询验证。
用
AND/OR组合。不确定优先级时加括号。
执行并验证。
避坑提醒:
AND的优先级高于OR,所以条件1 OR 条件2 AND 条件3会被解释为条件1 OR (条件2 AND 条件3)。建议始终用括号明确逻辑。
我的踩坑经历:我写过
WHERE shop_name = '女装旗舰店' OR shop_name = '男装专营店' AND amount > 500,结果只筛选出男装专营店中金额>500的,女装旗舰店全部返回了。因为AND优先级高,实际是shop_name = '女装旗舰店' OR (shop_name = '男装专营店' AND amount > 500)。加上括号(shop_name = '女装旗舰店' OR shop_name = '男装专营店') AND amount > 500才是我想要的。
BETWEEN区间筛选
6.1 基础语法
WHERE列BETWEEN下界AND上界;等价于列 >= 下界 AND 列 <= 上界,包含边界值。
6.2 电商实操案例
案例一:查询金额在100到300元之间的订单(包含边界)
SELECT*FROMordersWHEREamountBETWEEN100AND300;预期结果:ORD001(299)、ORD002(189)、ORD004(399? 399不在100-300之间,所以不包括)、ORD009(259) → 实际ORD004=399不在,ORD009=259在。重新确认:ORD001(299)是,ORD002(189)是,ORD009(259)是。ORD004(399)不是。
案例二:查询2025年6月3日到6月4日的订单
SELECT*FROMordersWHEREcreate_timeBETWEEN'2025-06-03 00:00:00'AND'2025-06-04 23:59:59';预期结果:ORD004(6月3日14:20)、ORD005(6月3日16:00)、ORD006(6月4日08:30)、ORD007(6月4日10:00)。
6.3 避坑提醒
BETWEEN包含边界值,如果不想包含,用>和<组合。日期区间建议用
>= start AND < end + 1,避免漏掉当天的23:59:59之后的记录。例如WHERE create_time >= '2025-06-03' AND create_time < '2025-06-05'。
实操避坑提醒:
BETWEEN对日期时间类型要小心,因为时间精度可能到秒。最好用>=和<配合。
IN集合筛选
7.1 基础语法
WHERE列IN(值1,值2,...);等价于多个OR条件。
7.2 电商实操案例
案例一:查询女装旗舰店和男装专营店的订单
SELECT*FROMordersWHEREshop_nameIN('女装旗舰店','男装专营店');案例二:查询订单状态为“已支付”或“已完成”的订单
SELECT*FROMordersWHEREorder_statusIN('已支付','已完成');预期结果:除已取消外的所有订单。
案例三:查询商品名称为特定几个商品的订单
SELECT*FROMordersWHEREproduct_nameIN('碎花连衣裙','牛仔裤','雪纺衫');7.3 分步操作
列出需要匹配的值。
用
IN替换多个OR,提高可读性。执行验证。
避坑提醒:
IN列表中的值类型要与列类型一致。如果列表很长,考虑用子查询(后续会讲)。
LIKE模糊查询
8.1 基础语法
WHERE列LIKE'模式';%:匹配任意个字符(包括0个)。_:匹配单个字符。
8.2 电商实操案例
案例一:查询商品名称中包含“T恤”的订单
SELECT*FROMordersWHEREproduct_nameLIKE'%T恤%';预期结果:ORD002(纯棉T恤)、ORD005(儿童T恤)。
案例二:查询商品名称以“雪纺”开头的订单
SELECT*FROMordersWHEREproduct_nameLIKE'雪纺%';预期结果:ORD004(雪纺衫)。
案例三:查询商品名称中第二个字是“裙”的订单(第一个字任意)
SELECT*FROMordersWHEREproduct_nameLIKE'_裙%';预期结果:ORD001(碎花连衣裙)、ORD006(真丝连衣裙)。
8.3 分步操作
确定要模糊匹配的模式。
用
%代表任意长度,_代表单个字符。注意转义字符(如
\%匹配字面%)。
避坑提醒:
LIKE默认不区分大小写(MySQL),但区分字符集。以
%开头的模式无法使用索引,性能差。尽量避免在大量数据上用LIKE '%keyword%'。
我的踩坑经历:我曾用
LIKE '%连衣裙%'去匹配商品名称,结果把“连衣裙”和“雪纺连衣裙”都找到了,但查询跑了10秒。后来加了全文索引才改善。模糊查询前%会导致全表扫描,谨慎使用。
IS NULL / IS NOT NULL空值筛选
9.1 基础语法
WHERE列ISNULL;WHERE列ISNOTNULL;注意:不能写成= NULL,因为NULL代表“未知”,任何与NULL的比较结果都是NULL(假)。
9.2 电商实操案例
订单表中有product_name为NULL的行(ORD008)。
案例一:查询商品名称为空的订单
SELECT*FROMordersWHEREproduct_nameISNULL;预期结果:ORD008。
案例二:查询商品名称不为空的订单
SELECT*FROMordersWHEREproduct_nameISNOTNULL;预期结果:除ORD008外的所有订单。
9.3 分步操作
确认哪些字段允许NULL。
用
IS NULL或IS NOT NULL筛选。注意:
NULL不能用=判断。
避坑提醒:
在统计中,
COUNT(column)会忽略NULL值,COUNT(*)不会。空字符串
''不是NULL,需要用= ''判断。
综合实操案例:618大促高价值订单与异常数据排查
10.1 案例背景
某服饰类目店铺618大促后需要完成以下分析:
筛选出女装类目中金额≥500元的高价值订单。
筛选出6月1日至6月3日之间男装专营店的已支付订单。
找出商品名称中包含“连衣裙”且金额大于300元的订单。
找出订单状态为空(NULL)的异常订单(假设有)。
找出金额在100到200之间或金额大于1000的订单。
找出收货地址(本例没有,改用product_name)为NULL的异常数据。
10.2 分步操作
步骤1:高价值女装订单
SELECT*FROMordersWHEREshop_name='女装旗舰店'ANDamount>=500;预期结果:ORD006(1299)。
步骤2:男装专营店在特定日期的已支付订单
SELECT*FROMordersWHEREshop_name='男装专营店'ANDorder_status='已支付'ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-03';注意BETWEEN包含6月3日全天,而ORD003是6月2日,ORD009是6月5日,所以只有ORD003符合。
预期结果:ORD003(599)。
步骤3:商品名称包含“连衣裙”且金额>300
SELECT*FROMordersWHEREproduct_nameLIKE'%连衣裙%'ANDamount>300;预期结果:ORD006(真丝连衣裙,1299)。ORD001(碎花连衣裙)金额299不大于300,不包含。
步骤4:异常订单(product_name为空)
SELECT*FROMordersWHEREproduct_nameISNULL;预期结果:ORD008。
步骤5:金额100-200或大于1000
SELECT*FROMordersWHERE(amountBETWEEN100AND200)ORamount>1000;预期结果:金额100-200:ORD002(189)、ORD007(89? 89不在100-200)、ORD008(89不在)、ORD009(259不在) — 实际上只有ORD002=189?ORD009=259大于200,不属于。金额>1000:ORD006(1299)。所以结果为ORD002和ORD006。
步骤6:整合所有筛选条件(可选)
SELECT*FROMordersWHERE(shop_name='女装旗舰店'ANDamount>=500)OR(shop_name='男装专营店'ANDorder_status='已支付'ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-03')OR(product_nameLIKE'%连衣裙%'ANDamount>300)ORproduct_nameISNULL;10.3 结果验证
执行以上查询,核对行数和数据是否符合业务预期。
📌 电商数据合规提示:在筛选用户信息时,如果
user_id能关联到个人,筛选结果中不要直接导出用户ID明细,除非必要。另外,对product_name的模糊查询不会暴露敏感信息,但如果是用户昵称、地址等,要谨慎使用LIKE并限制结果集大小。
本章踩坑清单与合规总结
11.1 新手常见踩坑
| 错误 | 原因 | 正确做法 |
|---|---|---|
WHERE 列 = NULL | 不理解NULL特性 | 用IS NULL |
| 字符串值不加单引号 | 语法错误 | 加单引号 |
LIKE '%keyword'导致全表扫描 | 无法使用索引 | 尽量避免,或使用全文索引 |
AND/OR优先级混淆 | 缺少括号 | 用括号明确逻辑 |
BETWEEN包含边界误用 | 不想要边界值 | 用>=和< |
| 日期区间漏掉当天最后时刻 | 时间精度问题 | 用< '日期+1' |
11.2 性能优化建议
尽量在
WHERE中使用索引列。避免在条件中对列做函数转换(如
WHERE DATE(create_time) = '2025-06-01'),会导致索引失效。用
EXPLAIN查看执行计划,确认是否走索引。
结语
WHERE子句是SQL查询的灵魂。掌握比较、逻辑、区间、集合、模糊、空值六类条件筛选,你就能从海量数据中精准提取分析所需的数据行。
有问题的评论区留言,我看到会回复。
