between … and 在 sql 中包含边界,但对 null 返回 unknown 而被 where 过滤,且存在数据类型隐式转换风险;日期查询推荐左闭右开(>= and

BETWEEN ... AND 在 SQL 中确实能查区间值,但它默认包含边界,且对 NULL 和数据类型敏感——用错会漏数据或报错。
WHERE col BETWEEN low AND high 的真实行为
它等价于 WHERE col >= low AND col ,不是半开区间。这意味着 <code>BETWEEN 1 AND 10 会命中 1 和 10 本身。
- 如果
col是字符串(如'2023-01'),比较按字典序进行,BETWEEN '2023-01' AND '2023-12'会包含'2023-10'、'2023-11',但不会包含'2023-09'(因为'09' ,但字典序中 <code>'09' > '1'?不对——实际是'2023-01' 成立,所以没问题;真正风险在非标准格式如 <code>'2023/1') - 如果
low > high,整个条件恒为 FALSE(MySQL 允许但返回空结果;PostgreSQL 直接报错ERROR: invalid input syntax for type integer或类似) -
NULL永远不满足BETWEEN:哪怕col是 NULL,NULL BETWEEN 1 AND 10结果是UNKNOWN,被 WHERE 过滤掉
日期区间查询最容易踩的坑
用 BETWEEN '2023-01-01' AND '2023-12-31' 查全年数据,看似合理,但如果字段是 DATETIME 或 TIMESTAMP,而你存的是 '2023-12-31 14:22:05',它会被包含;但如果你本意是“截止到 2023-12-31 23:59:59”,而数据库里存在 '2023-12-31 23:59:59.999'(毫秒精度),BETWEEN 仍能覆盖——前提是你的类型支持该精度且字面量写对了。
- 更安全的做法是用左闭右开:
WHERE created_at >= '2023-01-01' AND created_at - MySQL 中
'2023-12-31'隐式转为'2023-12-31 00:00:00',所以BETWEEN '2023-01-01' AND '2023-12-31'实际查的是从当天零点到当天零点,丢掉一整天数据 - PostgreSQL 对字符串转日期更严格,
BETWEEN '2023-01-01' AND '2023-12-31'在DATE列上安全,在TIMESTAMP上仍需注意时区和隐式截断
替代方案:用 >= 和
尤其涉及时间、浮点或需要排除上界时,显式写范围比 BETWEEN 更少歧义。
- 查整点小时:用
WHERE event_time >= '14:00' AND event_time ,比 <code>BETWEEN '14:00' AND '14:59'可靠(避免漏掉'14:59:30') - 查数值近似范围:浮点列如
score REAL,BETWEEN 0.1 AND 0.2可能因精度丢失行为异常;改用>= 0.1 AND 或转成定点数比较 - 兼容性:所有 SQL 方言都支持
>=和,但某些嵌入式 SQL 引擎(如 SQLite 的某些旧驱动)对 <code>BETWEEN解析有 bug
真正麻烦的不是语法记不住,而是当字段类型和输入格式不一致时,BETWEEN 会静默转类型再比较——比如把字符串 '100' 和整数 99 比,可能按字符串比('100' 为真),也可能转整数(取决于数据库和上下文)。动手前先 <code>SELECT typeof(col), length(col), col FROM t LIMIT 1 看一眼实际存储形态。










