between是闭区间,包含边界值;用于日期时需注意精度,推荐左闭右开写法;数值比较应避免隐式转换和浮点误差;复合条件须加括号;索引是否生效取决于字段是否被函数包裹、联合索引顺序及边界值可评估性。

WHERE子句里BETWEEN的边界到底包不包含?
BETWEEN是闭区间,BETWEEN 10 AND 20 等价于 col >= 10 AND col ,两端都包含。这不是“可能包含”,而是SQL标准强制行为——写错成 <code>> 10 AND 就会漏掉10和20这两条记录。
常见错误现象:查订单金额在100到500元之间,却写了 amount > 100 AND amount ,结果100元和500元的订单全被过滤掉。
- 左边界必须 ≤ 右边界,否则返回空集(MySQL不报错,但逻辑失效)
- 字符串比较按字典序,
'Bob' BETWEEN 'Alice' AND 'Charlie'成立,但'bob'是否成立取决于 collation(如utf8mb4_0900_as_cs区分大小写) - 字段为
NULL时,NULL BETWEEN 1 AND 10返回UNKNOWN,整行被过滤——不是bug,是三值逻辑必然结果
DATETIME字段用BETWEEN查“某一天”为什么总丢数据?
因为 '2024-06-01' 被隐式转成 '2024-06-01 00:00:00',而 '2024-06-01 14:30:22' > '2024-06-01',所以 create_time BETWEEN '2024-06-01' AND '2024-06-01' 实际只匹配零点那一条。
正确做法不是硬补 '23:59:59'(微秒场景下仍可能漏),而是改用左闭右开:create_time >= '2024-06-01' AND create_time 。
- DATE类型字段(无时间部分)可安全用
BETWEEN '2024-06-01' AND '2024-06-01',但统一风格建议也用 >= + - 如果必须用BETWEEN查完整一天,显式写满时间:
BETWEEN '2024-06-01 00:00:00' AND '2024-06-01 23:59:59.999999'(MySQL 5.6.4+支持微秒) - 避免用
DATE(create_time) = '2024-06-01'——函数运算导致索引失效
数值精度与类型不一致引发的隐式转换坑
当字段是 DECIMAL(10,2),而你传入字符串 '100' 或整数 100,MySQL会做隐式转换,但精度对齐可能出问题。更隐蔽的是浮点字段(FLOAT/DOUBLE)用BETWEEN,因二进制表示误差,amount BETWEEN 0.1 AND 0.3 可能漏掉本该匹配的 0.2。
- 数值字段配数字字面量:
amount BETWEEN 100.00 AND 500.00,别用'100' - 业务上允许NULL且需包含,得额外加
OR amount IS NULL,BETWEEN本身不处理NULL - 复合条件注意优先级:
status = 'paid' OR amount BETWEEN 100 AND 500必须加括号,否则等价于(status = 'paid' OR amount BETWEEN 100 AND 500)—— 实际执行顺序可能偏离预期
BETWEEN在索引上为啥有时不走range扫描?
理论上BETWEEN能触发范围索引扫描,但优化器实际是否选择它,取决于边界值是否可评估、字段是否被函数包裹、联合索引顺序是否满足最左前缀原则。
-
YEAR(create_time) BETWEEN 2023 AND 2024→ 字段套函数,索引完全失效 - 联合索引
(a, b, c),查询WHERE a = 1 AND c BETWEEN 10 AND 20→c不是最左前缀后连续字段,只能用到a,c部分退化为过滤 - 边界值来自参数(如预编译中的 ?)或子查询时,优化器无法准确估算选择率,可能放弃索引选全表扫描
真正容易被忽略的是:BETWEEN只是语法糖,底层仍靠优化器决策;比起迷信写法,更应看 EXPLAIN 的 type 和 key 列——别只盯着SQL长得像范围查询。











