MySQL用YEAR()提取年份最直接,PostgreSQL需EXTRACT(YEAR FROM date)并转INT,SQLite须strftime('%Y', date);三者语法不兼容,建议在应用层处理时间逻辑。

MySQL里用YEAR()提取年份最直接
如果字段是DATETIME或DATE类型,YEAR(date_column)就是最省事的写法。它不关心时区、不依赖格式,纯看日期值本身。
常见错误是传入字符串——比如YEAR('2023-10-05')在严格模式下会报Incorrect datetime value,因为MySQL试图隐式转换但失败了。必须确保输入是合法日期类型值,不是随便拼的字符串。
- 正确:
SELECT YEAR(created_at) FROM orders;(假设created_at是DATETIME) - 错误:
SELECT YEAR('2023/10/05');(斜杠分隔+无类型上下文,易出错) - 稳妥替代:
YEAR(STR_TO_DATE('2023/10/05', '%Y/%m/%d')),但没必要绕这么远
PostgreSQL没有YEAR(),得用EXTRACT()
PostgreSQL不认YEAR()函数,硬写会报错function year(timestamp without time zone) does not exist。必须改用标准SQL的EXTRACT(YEAR FROM date_column)。
注意EXTRACT()返回的是double precision类型,不是整数,排序或比较时一般不影响,但如果后续要拼接字符串(比如CONCAT(EXTRACT(YEAR FROM ...), '-Q1')),得显式转成INT或TEXT,否则可能触发隐式转换警告。
- 正确:
SELECT EXTRACT(YEAR FROM order_date)::INT FROM sales; - 也行:
SELECT DATE_PART('year', order_date)::INT FROM sales;(DATE_PART是PostgreSQL别名,行为一致) - 别漏
::INT,尤其当结果要参与GROUP BY或ORDER BY时
SQLite里不能用YEAR(),得靠strftime()
SQLite压根没YEAR()这个函数,直接写会报no such function: YEAR。它的日期函数全靠strftime()字符串格式化实现,语法是strftime('%Y', date_column)。
关键点在于:strftime()要求输入是符合ISO8601格式的字符串(如'2023-10-05'或'2023-10-05 14:30:00')。如果原始字段是Unix时间戳(整数秒),得先用datetime(unix_timestamp, 'unixepoch')转成字符串再取年。
- 日期字段直接用:
SELECT strftime('%Y', shipped_date) FROM shipments; - 时间戳字段要两步:
SELECT strftime('%Y', datetime(created_ts, 'unixepoch')) FROM logs; - 别写
strftime('%Y', '2023-10-05')——看着对,但万一字段里混了NULL或非法格式,strftime()静默返回NULL,不易排查
跨数据库兼容写法其实很脆弱
想写一条SQL在MySQL、PostgreSQL、SQLite里都跑通?基本做不到。三者函数名、参数顺序、空值处理逻辑全不同。硬套CASE WHEN判断数据库类型反而让SQL变臃肿、难维护。
真正该做的是:在应用层(比如Python的SQLAlchemy、Java的JDBC)根据方言动态生成SQL片段;或者把年份提取逻辑移到代码里处理——数据库只负责存原始时间,年份由业务层解析,更可控也更容易测试。
很多人卡在“为什么同一句SQL换个库就报错”,问题不在函数记不牢,而在默认把数据库当万能计算器用了。时间处理这种带语义的操作,越早移出SQL,后期越省心。

















