EXTRACT 能提取 YEAR、MONTH、DAY、HOUR、MINUTE、SECOND、DOY、DOW、WEEK 等预定义字段,不支持季度或年月等组合值;PostgreSQL 要求字段名大写,MySQL/SQLite 大小写不敏感但推荐大写;SQLite 不支持 EXTRACT,需用 strftime;EXTRACT 返回数值型,生成字符串格式需用 TO_CHAR、DATE_FORMAT 或 strftime。

EXTRACT 能提取哪些日期部分?
EXTRACT 只能提取预定义的字段,比如 YEAR、MONTH、DAY、HOUR、MINUTE、SECOND,还有 DOY(一年中的第几天)、DOW(星期几,0=Sunday)、WEEK 等。它不支持直接提取“季度”或“年月”这种组合值,也不能用 EXTRACT(QUARTER FROM ...) 以外的自定义格式。
不同数据库对字段名大小写敏感程度不同:PostgreSQL 要求全大写(YEAR),MySQL 和 SQLite 接受大小写混合(但推荐统一用大写避免歧义)。
常见错误现象:ERROR: invalid argument for EXTRACT() 或 Unknown column 'year' in field list,多半是字段名拼错(比如写成 year 小写)或用了不支持的字段(如 QUARTER 在 SQLite 中不可用)。
PostgreSQL / MySQL 中提取年月日的写法差异
PostgreSQL 严格遵循 SQL 标准,语法统一:
SELECT EXTRACT(YEAR FROM order_date) AS y,
EXTRACT(MONTH FROM order_date) AS m,
EXTRACT(DAY FROM order_date) AS d
FROM orders;
MySQL 支持 EXTRACT,但更常用 YEAR()、MONTH()、DAY() 函数——它们性能略好,且语义更直白:
-
EXTRACT(YEAR FROM date_col)和YEAR(date_col)结果一样,但后者在 MySQL 中解析更快 -
EXTRACT在 MySQL 中要求第一个参数必须是日期时间类型;如果传入字符串(如'2023-04-01'),需先用STR_TO_DATE()转换,否则返回NULL - SQLite 不支持
EXTRACT,得用strftime('%Y', date_col)替代
为什么不能用 EXTRACT 提取“年月”字符串?
EXTRACT 返回的是数值类型(integer),不是字符串。想得到 '2023-04' 这种格式,不能写 EXTRACT(YEAR_MONTH FROM ...)——这个字段根本不存在,会报错。
正确做法取决于数据库:
- PostgreSQL:
TO_CHAR(order_date, 'YYYY-MM') - MySQL:
DATE_FORMAT(order_date, '%Y-%m')或CONCAT(YEAR(order_date), '-', LPAD(MONTH(order_date), 2, '0')) - SQLite:
strftime('%Y-%m', date_col)
硬拼 EXTRACT(YEAR FROM ...) || '-' || EXTRACT(MONTH FROM ...) 看似可行,但月份可能变成 '2023-4'(缺前导零),排序和比较会出问题。
时区和 TIMESTAMP WITH TIME ZONE 的影响
如果字段类型是 TIMESTAMP WITH TIME ZONE(PostgreSQL),EXTRACT 默认按数据库当前时区计算。例如 UTC 时间 2023-01-01 23:00:00+00 在上海时区(+8)下,EXTRACT(DAY FROM ...) 会返回 2,而不是 1。
要确保一致性,建议:
- 显式转换时区:
EXTRACT(DAY FROM order_date AT TIME ZONE 'UTC') - 或先用
date_trunc('day', order_date AT TIME ZONE 'UTC')截断再提取 - 避免在 WHERE 条件中对带时区字段做
EXTRACT运算,否则可能无法走索引
真正容易被忽略的是:同一个 order_date 值,在不同时区设置下,EXTRACT(YEAR FROM ...) 可能返回不同结果——尤其跨年临界点(如 UTC 时间 2023-12-31 23:00:00 在东京是 2024-01-01)。

















