今天我们继续深入玩时间数据,学会怎么用 EXTRACT() 从里面抠出具体的部分(比如年份、月份或者星期几),还要看看怎么用 AGE() 算年龄或者两个日期之间的间隔。
在实际项目里,处理时间数据经常需要把日期或时间拆开来用。比如:
- 按年份或月份把订单分组;
- 统计某个星期几注册的用户数量;
- 分析两个事件之间的持续时间。
这些需求我们都可以用 EXTRACT() 和 AGE() 这俩函数搞定。
啥是 EXTRACT()?
EXTRACT() 这个函数能从日期或时间戳里抠出你想要的那一部分。比如你可以拿到生日的年份、月份,甚至星期几。
语法:
EXTRACT(part FROM source)
part:你想提取的日期部分。可以是YEAR、MONTH、DAY、HOUR、MINUTE、SECOND等等。source:你要提取信息的时间类型数据。可以是表里的字段、常量或者函数的结果。
例子1:提取年、月、日
SELECT
EXTRACT(YEAR FROM '2024-11-15'::DATE) AS year_part,
EXTRACT(MONTH FROM '2024-11-15'::DATE) AS month_part,
EXTRACT(DAY FROM '2024-11-15'::DATE) AS day_part;
结果:
| year_part | month_part | day_part |
|---|---|---|
| 2024 | 11 | 15 |
这里我们从 2024-11-15 这天提取了年、月、日。这个方法很适合你要按日期的某一部分分组数据的时候用。
例子2:提取星期几和小时
SELECT
EXTRACT(DOW FROM '2024-11-15'::DATE) AS day_of_week,
EXTRACT(HOUR FROM '15:30:00'::TIME) AS hour_part;
结果:
| day_of_week | hour_part |
|---|---|
| 3 | 15 |
DOW(Day of Week) 返回星期几的编号:周日是0,周一是1,以此类推。HOUR就是从时间里抠出小时数。
例子3:对表字段用 EXTRACT()
假如我们有个带日期的表,比如 orders:
| order_id | order_date |
|---|---|
| 1 | 2023-05-12 14:20 |
| 2 | 2023-06-18 10:45 |
| 3 | 2023-07-22 21:15 |
SELECT
order_id,
EXTRACT(MONTH FROM order_date) AS month,
EXTRACT(DAY FROM order_date) AS day
FROM orders;
结果:
| order_id | month | day |
|---|---|---|
| 1 | 5 | 12 |
| 2 | 6 | 18 |
| 3 | 7 | 22 |
啥是 AGE()?
AGE() 这个函数用来算两个时间戳之间的差值。比如你可以用它算客户的年龄,或者某个订单到现在过了多久。
语法:
AGE(timestamp1, timestamp2)
timestamp1:较晚的时间戳。timestamp2:较早的时间戳。- 如果只写一个参数,PostgreSQL 会自动用当前时间(
NOW())和它比。
例子1:算年龄
SELECT AGE('2025-11-15'::DATE, '1990-05-12'::DATE) AS age;
结果:
| age |
|---|
| 35 years 6 mons |
这个例子就是算一个 1990 年 5 月 12 日出生的人,到 2025 年 11 月 15 日的年龄。
例子2:算事件间隔
SELECT AGE('2023-06-01 15:00'::TIMESTAMP, '2023-05-20 10:30'::TIMESTAMP) AS duration;
结果:
| duration |
|---|
| 11 days 4:30:00 |
这里我们算了两个事件之间的时间间隔。比如你要算任务开始到结束用了多久,这就很方便。
例子3:客户年龄
假如我们有个 customers 表:
| customer_id | birth_date |
|---|---|
| 1 | 1992-03-10 |
| 2 | 1985-07-07 |
我们可以这样算客户的年龄:
SELECT
customer_id,
AGE(NOW(), birth_date) AS age
FROM customers;
2025年6月13日的结果:
| customer_id | age |
|---|---|
| 1 | 33 years 3 mons |
| 2 | 39 years 11 mons |
当然你自己的 NOW() 值和结果会不一样哈。
EXTRACT() 和 AGE() 的实用例子
现在我们把这俩函数放到实际场景里玩玩。
例子1:按月份分组统计
假如有个订单表带日期,想统计每月订单数,可以这样写:
SELECT
EXTRACT(MONTH FROM order_date) AS order_month,
COUNT(*) AS total_orders
FROM orders
GROUP BY order_month
ORDER BY order_month;
例子2:距离到期还有几天
比如有个 subscriptions 表:
| subscription_id | expiry_date |
|---|---|
| 1 | 2023-12-31 |
| 2 | 2024-05-15 |
我们想知道每个订阅距离到期还有多久:
SELECT
subscription_id,
AGE(expiry_date, NOW()) AS time_remaining
FROM subscriptions;
结果:
| subscription_id | time_remaining |
|---|---|
| 1 | 1 mons 15 days |
| 2 | 6 mons |
常见坑和怎么避开
用 EXTRACT() 和 AGE() 的时候,新手经常会踩这些坑:
- 想从
TIME类型里抠月份啥的,这不行。记住:YEAR、MONTH、DAY这些只能用在DATE、TIMESTAMP,不能用在TIME。 - 时间数据格式不对。比如
2023/11/15这种字符串不是标准日期。要用::DATE或TO_DATE()转一下类型。 AGE()和直接减时间戳的区别。如果你要精确的间隔(比如几个月、几天、几秒)用AGE(),要是只想知道天数,直接减就行。
现在你已经有了用 PostgreSQL 提取和分析时间数据的所有技能。赶紧在自己的项目里试试 EXTRACT() 和 AGE() 吧!
GO TO FULL VERSION