MySQL如何查询日期?

来源:安卓APP网作者:闲进程头衔:程序员
导读:本期聚焦于闲进程创作的《MySQL如何查询日期?》,敬请观看详情。在MySQL里按日期查数据,最容易出错的地方往往不是语法,而是对日期类型的边界和比较规则理解不到位。比如用DATE函数包裹DATETIME列做等值筛选,虽然逻辑正确,却可能让索引完全失效。本文先梳理DATE、DATETIME、TIMESTAMP等类型的存储差异和时区行为,再结合CURDATE、DATE_FORMAT、STR_TO_DATE、DATE_ADD等函数说明常见查询写法。随后重点演示如何用半开区间查询某一天、某一月的数据,避免BETWEEN和函数转换导致的精度或性能问题。最后讨论按日期分组统计的实现方式和优化思路,包括日期维度表、时区转换等实战细节。读完能建立一套从类型选择到索引友好的日期查询方法,少踩一些隐式转换和时区偏移的坑。

在MySQL数据库里,日期和时间相关的查询几乎出现在每一张业务表中。订单创建时间、用户注册日期、日志记录时间,这些字段的筛选、统计和格式化需求非常普遍。但很多查询看似简单,一旦涉及日期类型选择、时区处理或索引利用,就会出现结果偏差或性能瓶颈。本文从日期类型、常用函数、范围查询、分组统计和时区转换几个方面,系统梳理MySQL日期查询的实用方法。

MySQL如何查询日期?

一、先分清MySQL的日期类型

MySQL提供多种日期和时间类型,常见的有DATE、DATETIME、TIMESTAMP、TIME和YEAR。DATE只存储年月日,范围从1000-01-01到9999-12-31;DATETIME存储年月日时分秒,范围与DATE一致;TIMESTAMP范围较小,从1970-01-01 00:00:01 UTC到2038-01-19 03:14:07 UTC,且与时区相关。TIME可以表示时间间隔或一天中的时间,范围从-838:59:59到838:59:59;YEAR只存储年份。

很多人容易混淆DATETIME和TIMESTAMP。核心差异是TIMESTAMP在写入和读取时会根据会话时区自动转换,而DATETIME存什么读出来就是什么。因此记录业务发生时间且需要跨时区展示时,TIMESTAMP更灵活,但要注意2038年限制;如果只是记录一个固定时间点且不关心时区,用DATETIME更直观。

最不推荐的做法是用VARCHAR类型保存日期字符串。这样做会导致日期函数无法直接使用,比较和排序也只能按字典序进行,例如字符串的10月会排在2月前面。下面给出一个规范的表结构示例:

CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    order_date DATE,
    created_at DATETIME,
    updated_at TIMESTAMP
);

二、掌握核心日期函数

MySQL内置了大量日期函数,最常用的包括NOW()、CURDATE()、CURTIME()、DATE()、YEAR()、MONTH()、DAY()等。NOW()返回当前日期和时间,CURDATE()只返回当前日期,CURTIME()只返回当前时间。DATE()可以从DATETIME中截取日期部分,YEAR()、MONTH()、DAY()则分别提取年、月、日。

格式化日期通常使用DATE_FORMAT()函数,它支持类似%Y代表四位年份、%m代表两位月份、%d代表两位日期、%H代表24小时制小时、%i代表分钟、%s代表秒的格式符。反过来,STR_TO_DATE()可以把字符串按指定格式解析成日期。下面是一个典型示例,同时展示提取和格式化:

SELECT 
    id,
    created_at,
    DATE(created_at) AS only_date,
    YEAR(created_at) AS order_year,
    MONTH(created_at) AS order_month,
    DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') AS formatted_time
FROM orders;

日期计算方面,DATE_ADD()和DATE_SUB()可以在日期上加减指定的时间间隔,DATEDIFF()可以计算两个日期之间的天数差。比如要查询最近7天内的数据,可以先算好起始日期,再配合范围条件使用。

三、按日期范围查询的正确姿势

按日期范围查询是业务中最常见的需求,但写法不当会造成结果错误或索引失效。比如要查询某一天创建的订单,如果直接使用DATE(created_at) = '2025-01-01',逻辑上没错,但DATE()函数作用在created_at列上,MySQL无法使用该列上的索引,数据量大时查询会非常慢。

更合理的写法是使用半开区间,即大于等于当天零点并小于次日零点。这样既可以利用created_at上的索引,也能准确包含当天所有时间记录。示例如下:

SELECT * 
FROM orders
WHERE created_at >= '2025-01-01 00:00:00'
  AND created_at < '2025-01-02 00:00:00';

对于BETWEEN ... AND ...,虽然写起来简单,但它在日期范围查询中容易把边界值重复包含或误包含。尤其是当字段带有时间部分时,BETWEEN '2025-01-01' AND '2025-01-31' 会漏掉1月31日当天除了零点以外的数据。因此涉及日期范围时,优先使用大于等于和小于组合。

四、日期分组统计并避开性能坑

按日期分组统计是报表系统的刚需。要统计每天的订单量,可以使用GROUP BY DATE(created_at);如果要按月统计,可以用DATE_FORMAT(created_at, '%Y-%m')作为分组键。下面是一个按月统计订单数量的例子:

SELECT 
    DATE_FORMAT(created_at, '%Y-%m') AS month,
    COUNT(*) AS order_count
FROM orders
GROUP BY DATE_FORMAT(created_at, '%Y-%m')
ORDER BY month;

不过这种分组方式在数据量很大时性能一般,因为DATE_FORMAT()也是函数操作,会阻止索引的有序性利用。更优的做法是先按日期范围切分,再在应用层汇总,或者引入一张日期维度表,关联后按日期维度字段分组。日期维度表通常包含连续日期、所属周、月、季度、是否工作日等属性,既能提升查询效率,也能简化统计逻辑。

如果只需要统计某个月的数据,可以先确定该月的起止时间,再用范围条件过滤后COUNT,而不是对整个表做GROUP BY。例如统计2025年1月的订单量,可以写成:

SELECT COUNT(*) AS order_count
FROM orders
WHERE created_at >= '2025-01-01 00:00:00'
  AND created_at < '2025-02-01 00:00:00';

五、时区与格式转换注意事项

时区处理是日期查询中另一个容易踩坑的地方。TIMESTAMP类型的值在存储时会从当前会话时区转换为UTC,读取时再从UTC转换回当前会话时区。这意味着同一个TIMESTAMP字段在不同时区的客户端可能显示不同时间。DATETIME则不会自动转换。如果需要把某个时间从一时区转换到另一时区,可以使用CONVERT_TZ()函数。

例如把UTC时间转换为北京时间,可以写成:

SELECT 
    CONVERT_TZ('2025-01-01 08:00:00', '+00:00', '+08:00') AS beijing_time;

处理从外部系统导入的日期字符串时,STR_TO_DATE()非常有用,但要注意格式必须与字符串完全匹配,否则返回NULL。对于无效日期,MySQL默认在严格模式下会报错,在非严格模式下可能转换为零日期0000-00-00。建议在应用层或导入前先做好日期格式校验,减少数据库侧的异常。

最后提醒一点,日期函数虽强大,但在WHERE条件中应尽量避免对列使用函数,除非该列没有索引或数据量很小。否则应改写为范围条件,让索引发挥作用。这个原则适用于DATE()、DATE_FORMAT()、YEAR()等所有函数操作。

MySQL日期查询日期函数修改时间:2026-09-22 04:39:49

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0922/60338.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。