导读:本期聚焦于新井创作的《SQL中如何用YEAR和MONTH函数提取日期中的年份和月份?》,敬请观看详情。从日期字段中拆出年份和月份是 SQL 报表查询里出现频率很高的需求。YEAR() 和 MONTH() 是两个专用标量函数,接收日期、日期时间或可隐式转换的字符串,返回对应的整数值。不同数据库的实现略有差异:MySQL 和 SQL Server 直接支持 YEAR()、MONTH();PostgreSQL 与 Oracle 更推荐使用 EXTRACT 或 DATE_PART。掌握这两个函数后,可以轻松完成按年按月筛选、分组统计以及生成年度或月度报表。需要留意的是,在 WHERE 条件中直接对日期列套用函数可能导致索引失效,数据量大时可采用范围条件替代,或用生成列、函数索引进行优化。本文通过基础语法、数据库差异和实战示例,把 YEAR、MONTH 的各类用法讲透,帮助你在不同 SQL 环境下正确提取日期中的年月信息。

在 SQL 中处理日期数据时,经常需要从完整的日期值里单独拿到年份或月份,比如统计某一年注册的用户数、按月汇总订单金额,或者判断某个日期是否属于目标月份。YEAR() 和 MONTH() 就是完成这类任务最直接的两个标量函数。它们通常接收 DATE、DATETIME、TIMESTAMP 类型的表达式,也可以接收能隐式转换为日期类型的字符串,返回结果分别是四位整数年份和一到两位整数月份。本文会结合 MySQL、SQL Server 等常见数据库,把这两个函数的用法、差异以及容易踩到的坑一次讲清楚。

SQL中如何用YEAR和MONTH函数提取日期中的年份和月份?

YEAR 和 MONTH 的基础语法与数据库差异

在 MySQL、MariaDB 和 SQL Server 中,YEAR() 和 MONTH() 的语法非常相近:YEAR(日期表达式) 返回该日期对应的四位年份,MONTH(日期表达式) 返回一到十二之间的月份整数。以 MySQL 为例,下面的查询可以直接把字符串日期拆成年和月。

-- MySQL / MariaDB 基础用法
SELECT YEAR('2024-03-15') AS year_value,
       MONTH('2024-03-15') AS month_value;

执行后会得到 year_value 为 2024,month_value 为 3。对于 DATETIME 或 TIMESTAMP 类型的列,两个函数同样适用。假设 orders 表中存在 created_at 列,就可以在 SELECT、WHERE、GROUP BY、ORDER BY 中直接使用它们。需要理解的是,这类函数返回整数,不保留前导零,例如 3 月返回的是 3 而不是 03,因此在报表展示时如果要求月份固定两位,通常还需要做补零处理。

SQL Server 的写法基本一致,可以直接对日期列调用 YEAR 和 MONTH。此外 SQL Server 还提供了 DATEPART(year, created_at) 和 DATEPART(month, created_at),效果等价。PostgreSQL 和 Oracle 则更偏向标准 SQL 的 EXTRACT 表达式,虽然有些环境也可能通过扩展支持 YEAR 函数,但在跨数据库场景下建议优先使用 EXTRACT。

-- SQL Server 写法
SELECT YEAR(created_at) AS order_year,
       MONTH(created_at) AS order_month
FROM orders;
-- PostgreSQL / Oracle 推荐写法
SELECT EXTRACT(YEAR FROM created_at) AS order_year,
       EXTRACT(MONTH FROM created_at) AS order_month
FROM orders;

如果习惯使用 PostgreSQL 的 DATE_PART,也可以写成 DATE_PART('year', created_at),效果与 EXTRACT 类似。至于 SQLite,虽然不直接支持 YEAR 函数,但可以用 STRFTIME('%Y', 日期字段) 实现相同目的。了解这些差异后,在切换数据库或者阅读不同项目代码时就不容易混淆。

筛选、分组与报表中的实战用法

只提取年月往往不是最终目的,更有价值的是把提取结果用于筛选和聚合。例如要查询 2024 年创建的所有订单,最直观的写法是把 YEAR(created_at) 直接放进 WHERE 子句。

-- 按年份筛选订单
SELECT order_id, customer_id, created_at
FROM orders
WHERE YEAR(created_at) = 2024;

这种写法可读性好,但如果 created_at 列上建立了索引,函数作用在列上会导致优化器很难利用索引进行范围扫描。数据量较大时,不建议把它作为第一选择。更稳妥的方式是用明确的日期范围条件,让查询保持可索引。

-- 用范围条件替代函数筛选,更利于索引
SELECT order_id, customer_id, created_at
FROM orders
WHERE created_at >= '2024-01-01'
  AND created_at < '2025-01-01';

在报表统计中,按月分组几乎是 YEAR 和 MONTH 的经典组合。下面按用户注册年月统计数量,很多后台看板都是这种输出形式。分组时需要注意,SELECT 中出现没有包含在聚合函数里的列,必须同时出现在 GROUP BY 中,否则严格模式下会直接报错。

-- 按年和月统计注册用户数
SELECT YEAR(reg_time) AS reg_year,
       MONTH(reg_time) AS reg_month,
       COUNT(*) AS user_count
FROM users
GROUP BY YEAR(reg_time), MONTH(reg_time)
ORDER BY reg_year, reg_month;

如果希望月份显示为两位数字,MySQL 可以借助 LPAD 处理,例如 LPAD(MONTH(reg_time), 2, '0'),其他数据库也都有对应的补零函数。需要生成“2024-03”这种年月组合时,可以用 CONCAT 或字符串拼接。

-- MySQL 生成 2024-03 格式的年月
SELECT CONCAT(YEAR(created_at), '-', LPAD(MONTH(created_at), 2, '0')) AS month_key
FROM orders;

这种年月键值在制作折线图、柱状图或月度对比表时非常实用,尤其是配合 ORDER BY 排序后,前端可以直接使用稳定格式的月份标识。

常见陷阱:字符串格式、空值和对索引的影响

YEAR 和 MONTH 虽然简单,但在实际项目里仍然有几个容易出错的地方。第一个是字符串格式问题。MySQL 对日期字符串的解析能力并不稳定,标准格式 yyyy-mm-dd 通常可以正确转换,但用斜杠分隔的字符串在部分配置或严格模式下可能返回 NULL。

-- MySQL 中不同日期格式的解析差异
SELECT YEAR('2024-03-15') AS y1,
       MONTH('2024-03-15') AS m1,
       YEAR('2024/03/15') AS y2,
       MONTH('2024/03/15') AS m2;

如果查询结果里 y2、m2 是 NULL,说明字符串没有被识别为有效日期。处理办法是使用 STR_TO_DATE 明确转换,例如 STR_TO_DATE('2024/03/15', '%Y/%m/%d'),然后再套用 YEAR、MONTH。这样无论原始字符串是什么分隔方式,都能得到稳定的年份和月份。

第二个是空值问题。任何标量函数遇到 NULL 输入基本都会返回 NULL,如果不加处理,报表里可能出现空白值。可以在 SELECT 阶段用 CASE 或数据库提供的 COALESCE 函数兜底。

-- 空值处理示例
SELECT COALESCE(CAST(YEAR(created_at) AS CHAR), '未知年份') AS order_year
FROM orders;

第三个是索引失效问题,前面已经提到。如果必须保留索引效率,同时又希望使用函数式写法,可以考虑在表中增加生成列,或者使用函数索引。MySQL 8、SQL Server 支持生成列,PostgreSQL、Oracle 支持函数索引,这些方案都能在保证查询可读性的同时减少性能损耗。

-- MySQL 8 通过生成列优化年份筛选
ALTER TABLE orders
  ADD COLUMN order_year INT GENERATED ALWAYS AS (YEAR(created_at)) STORED,
  ADD INDEX idx_order_year (order_year);

总之,YEAR 和 MONTH 是日期处理中最基础也最常用的两个函数。理解它们的适用数据库、返回类型以及对查询计划的影响,能帮助你在日常开发中避开很多低效 SQL 和隐性错误。当遇到跨数据库需求时,善用 EXTRACT 和 DATE_PART 也能保持 SQL 的可移植性。

SQL日期提取YEAR函数MONTH函数修改时间:2026-10-05 13:02:08

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