between日期范围包含边界,等价于>=且=与

WHERE子句中用BETWEEN写日期范围最直观,但要注意边界包含性
直接用 BETWEEN '2023-01-01' AND '2023-12-31' 是常见写法,它等价于 date_column >= '2023-01-01' AND date_column ,两端都闭合。但问题在于:如果字段含时间(如 <code>DATETIME 或 TIMESTAMP),'2023-12-31' 会被隐式转成 '2023-12-31 00:00:00',导致当天 00:00:01 之后的数据被漏掉。
实操建议:
- 明确字段类型:用
DESCRIBE table_name或SHOW COLUMNS FROM table_name确认是DATE还是DATETIME - 若为
DATETIME,优先用开闭区间:date_column >= '2023-01-01' AND date_column - 避免依赖字符串自动转换,显式用
CAST('2023-01-01' AS DATE)或DATE('2023-01-01')提高可读性
MySQL里用STR_TO_DATE处理不规范日期字符串
当日期存为 VARCHAR(如 '01/15/2023' 或 '15-01-2023'),直接 WHERE date_str BETWEEN ... 会按字典序比较,结果不可靠。
必须先转成真实日期再比较:
- 用
STR_TO_DATE(date_str, '%m/%d/%Y')转'01/15/2023'→2023-01-15 - 格式符要严格匹配:年用
%Y(4位)或%y(2位),日用%d(补零)或%e(不补零) - 转失败时返回
NULL,所以加IS NOT NULL判断更安全:WHERE STR_TO_DATE(date_str, '%d-%m-%Y') >= '2023-01-01' AND STR_TO_DATE(date_str, '%d-%m-%Y') IS NOT NULL
PostgreSQL中日期范围过滤要小心时区
PostgreSQL 的 TIMESTAMP WITH TIME ZONE 类型在 WHERE 中参与比较时,会按当前会话时区做隐式转换,同一语句在不同时区服务器上可能返回不同结果。
稳妥做法:
- 统一转成 UTC 比较:
date_col AT TIME ZONE 'UTC' >= '2023-01-01' AND date_col AT TIME ZONE 'UTC' - 或强制会话时区:
SET TIME ZONE 'Asia/Shanghai';再执行查询(注意连接级生效) - 避免用
now() - INTERVAL '30 days'这类动态表达式做范围右边界——它每次执行值都变,不利于缓存和复现
WHERE里用函数包裹日期字段会导致索引失效
比如写成 WHERE YEAR(order_date) = 2023 或 WHERE DATE(created_at) = '2023-01-01',数据库无法使用 order_date 或 created_at 上的索引,全表扫描风险高。
正确姿势是把函数移到右边,让左边保持裸字段:
- ❌ 错误:
WHERE YEAR(created_at) = 2023 - ✅ 正确:
WHERE created_at >= '2023-01-01' AND created_at - ✅ 正确(PostgreSQL):
WHERE created_at >= '2023-01-01'::DATE AND created_at
哪怕日期格式不整齐,也宁可用 CAST 或 TO_DATE 先清洗数据,别在 WHERE 条件里对字段本身做计算。










