如何用WHERE子句查询特定日期区间内的数据?
- 内容介绍
- 相关推荐
本文共计932个文字,预计阅读时间需要4分钟。
直接使用`BETWEEN`查询可能遗漏当天全部数据,因为`BETWEEN`是闭区间,而数据库中的`DATETIME`字段默认包含时分秒,如`'2023-12-31 14:22:05'`。因此,应使用以下查询确保包含当天全部数据:
更稳妥的做法是用开闭区间:date_column >= '2023-01-01' AND date_column 。这样无论字段是 <code>DATE 还是 DATETIME,都能完整覆盖整个自然年。
- MySQL/PostgreSQL/SQL Server 都支持这种写法,语义清晰且可走索引
- 避免用
DATE(date_column) = '2023-01-01',它会让索引失效 - 如果字段允许 NULL,
BETWEEN会自动跳过这些行,而显式比较不受影响
日期字符串格式必须和字段类型对齐
传入的字符串格式不对,轻则查不到数据,重则触发隐式转换导致全表扫描。比如字段是 DATE 类型,写成 WHERE create_date = '2023-01-01 10:00:00',MySQL 可能转成 '2023-01-01',但 PostgreSQL 会直接报错或返回空。
安全做法是:用字段本身类型对应的最小粒度字符串。
-
DATE字段 → 用'2023-01-01'(ISO 格式,无歧义) -
DATETIME或TIMESTAMP字段 → 用'2023-01-01 00:00:00'或更精确的'2023-01-01T00:00:00'(部分数据库支持) - 别依赖
STR_TO_DATE()或TO_DATE()做运行时转换,除非输入确实是非标准格式字符串
时区问题让WHERE条件在跨区部署时行为不一致
如果数据库服务器、应用连接、客户端各自设了不同时区,'2023-01-01' 在 WHERE 中可能被解释成 UTC 时间,也可能被解释成本地时间。典型表现是:开发环境查得准,生产环境差一天。
关键不是“统一设时区”,而是“明确时区上下文”:
- 字段用
TIMESTAMP类型(MySQL)或TIMESTAMPTZ(PostgreSQL)——它们存的是 UTC,读取时按会话时区自动转换 - WHERE 条件里显式指定时区,如
created_at >= '2023-01-01'::timestamptz AT TIME ZONE 'Asia/Shanghai'(PostgreSQL) - 应用层传参前把时间转成 UTC 再拼进 SQL,比依赖数据库时区更可控
LIKE不能用于日期字段,但有人误写成WHERE date_col LIKE '2023%'
这是常见误操作。LIKE 是文本匹配操作符,对日期字段强制转字符串后执行,不仅性能极差,还会因格式差异失败——比如 MySQL 默认输出 '2023-01-01',而某些 JDBC 驱动可能返回 '2023-01-01 00:00:00.0','2023%' 就不匹配了。
真要按年/月过滤,应该用日期函数:
- MySQL:
YEAR(create_time) = 2023或DATE_FORMAT(create_time, '%Y-%m') = '2023-01' - PostgreSQL:
EXTRACT(YEAR FROM created_at) = 2023或to_char(created_at, 'YYYY-MM') = '2023-01' - 但注意:这些写法基本无法使用索引,大数据量慎用;优先考虑范围查询 + 覆盖索引
日期范围查询的核心不是语法多漂亮,而是每一步是否清楚自己在跟什么精度、什么时区、什么索引能力打交道。一个 比 <code> 多敲一个字符,却可能决定查询是毫秒级还是秒级。
本文共计932个文字,预计阅读时间需要4分钟。
直接使用`BETWEEN`查询可能遗漏当天全部数据,因为`BETWEEN`是闭区间,而数据库中的`DATETIME`字段默认包含时分秒,如`'2023-12-31 14:22:05'`。因此,应使用以下查询确保包含当天全部数据:
更稳妥的做法是用开闭区间:date_column >= '2023-01-01' AND date_column 。这样无论字段是 <code>DATE 还是 DATETIME,都能完整覆盖整个自然年。
- MySQL/PostgreSQL/SQL Server 都支持这种写法,语义清晰且可走索引
- 避免用
DATE(date_column) = '2023-01-01',它会让索引失效 - 如果字段允许 NULL,
BETWEEN会自动跳过这些行,而显式比较不受影响
日期字符串格式必须和字段类型对齐
传入的字符串格式不对,轻则查不到数据,重则触发隐式转换导致全表扫描。比如字段是 DATE 类型,写成 WHERE create_date = '2023-01-01 10:00:00',MySQL 可能转成 '2023-01-01',但 PostgreSQL 会直接报错或返回空。
安全做法是:用字段本身类型对应的最小粒度字符串。
-
DATE字段 → 用'2023-01-01'(ISO 格式,无歧义) -
DATETIME或TIMESTAMP字段 → 用'2023-01-01 00:00:00'或更精确的'2023-01-01T00:00:00'(部分数据库支持) - 别依赖
STR_TO_DATE()或TO_DATE()做运行时转换,除非输入确实是非标准格式字符串
时区问题让WHERE条件在跨区部署时行为不一致
如果数据库服务器、应用连接、客户端各自设了不同时区,'2023-01-01' 在 WHERE 中可能被解释成 UTC 时间,也可能被解释成本地时间。典型表现是:开发环境查得准,生产环境差一天。
关键不是“统一设时区”,而是“明确时区上下文”:
- 字段用
TIMESTAMP类型(MySQL)或TIMESTAMPTZ(PostgreSQL)——它们存的是 UTC,读取时按会话时区自动转换 - WHERE 条件里显式指定时区,如
created_at >= '2023-01-01'::timestamptz AT TIME ZONE 'Asia/Shanghai'(PostgreSQL) - 应用层传参前把时间转成 UTC 再拼进 SQL,比依赖数据库时区更可控
LIKE不能用于日期字段,但有人误写成WHERE date_col LIKE '2023%'
这是常见误操作。LIKE 是文本匹配操作符,对日期字段强制转字符串后执行,不仅性能极差,还会因格式差异失败——比如 MySQL 默认输出 '2023-01-01',而某些 JDBC 驱动可能返回 '2023-01-01 00:00:00.0','2023%' 就不匹配了。
真要按年/月过滤,应该用日期函数:
- MySQL:
YEAR(create_time) = 2023或DATE_FORMAT(create_time, '%Y-%m') = '2023-01' - PostgreSQL:
EXTRACT(YEAR FROM created_at) = 2023或to_char(created_at, 'YYYY-MM') = '2023-01' - 但注意:这些写法基本无法使用索引,大数据量慎用;优先考虑范围查询 + 覆盖索引
日期范围查询的核心不是语法多漂亮,而是每一步是否清楚自己在跟什么精度、什么时区、什么索引能力打交道。一个 比 <code> 多敲一个字符,却可能决定查询是毫秒级还是秒级。

