日期和时间可不只是抽象的数字,它们可是数据里超有价值的信息。在现实生活中你经常会碰到日期:比如按月份分析销售额、按员工生日过滤、或者比较时间区间。会玩日期,能让你写出更灵活的查询,还能搞定复杂的分析。
下面这些场景,日期操作就特别重要:
- 分析某个月的销售数据。
- 统计最近一年注册的用户数量。
- 按时间区间生成报表(比如每月收入)。
PostgreSQL有一堆处理日期的函数,这里我们只聊最有用的几个。
常用的日期和时间函数
NOW()函数会返回数据库服务器的当前日期和时间。你要知道精确的当前时间就用它。比如你想记录新订单的创建时间。
SELECT NOW();
结果示例:
2023-11-05 15:23:45.123456+00
用法示例:你想插入一条订单记录,带上当前的日期和时间:
INSERT INTO orders (order_id, order_date, total_amount)
VALUES (1, NOW(), 150.00);
注释:这里
NOW()会自动把当前日期和时间塞进
order_date这一列。
INSERT操作具体怎么玩,后面几节课你就懂了 :P
CURRENT_DATE函数
如果你只想要当前日期,不关心时间,就用CURRENT_DATE。它只会返回年、月、日。
语法:
SELECT CURRENT_DATE;
结果示例:
2023-11-05
用法示例:比如你想查今天的所有订单:
SELECT *
FROM orders
WHERE order_date = CURRENT_DATE;
注释:这里我们把
order_date这一列的日期和当前日期做对比。
来点幽默。NOW()就像你上班喝的咖啡:随时都能来一杯。而CURRENT_DATE就像墙上的日历:只有日期,没别的细节。
用DATE_PART()提取日期的部分
DATE_PART()函数能让你拿到日期里的某一部分,比如年、月、日、小时或者分钟。比如你想统计某一年的订单数,或者想知道星期几。
语法:
DATE_PART('部分', 日期)
例子:
SELECT DATE_PART('year', NOW()) AS current_year;
结果示例:
| current_year |
|---|
| 2025 |
可以提取的日期部分有:
year:年。month:月。day:日。hour:小时。minute:分钟。second:秒。dow:星期几(0 = 星期天)。
例子2:提取当前日期的月份。
SELECT DATE_PART('month', CURRENT_DATE) AS current_month;
结果:
| current_month |
|---|
| 6 |
DATE_PART()还能用来做复杂的计算。比如:
你想选出今年出生的所有学生:
SELECT *
FROM students
WHERE DATE_PART('year', birth_date) = DATE_PART('year', CURRENT_DATE);
结果示例:
| id | first_name | last_name | birth_date | grade |
|---|---|---|---|---|
| 1 | Otto | Art | 2025-03-12 | 9 |
| 2 | Anna | Pal | 2025-07-08 | 8 |
| 3 | Piu | Wolf | 2025-01-22 | 10 |
| 4 | Eva | Go | 2025-09-30 | 7 |
| 5 | Dan | Sok | 2025-06-14 | 9 |
实用例子
有些例子里会用到你还没学过的操作符。别慌,过一阵你就能轻松搞定这些例子啦。主要是想多给你展示点真实场景,也顺便吊你胃口 :)
例子1:算用户年龄
假设我们有个users表,里面有每个用户的生日。我们想算出他们的年龄。
查询:
SELECT user_id, first_name, last_name,
DATE_PART('year', CURRENT_DATE) - DATE_PART('year', birth_date) AS age
FROM users;
我们直接用当前年份减去出生年份。这样算年龄很快,但不是最精确的方式。
结果示例:
| user_id | first_name | last_name | age |
|---|---|---|---|
| 101 | Alex | Lin | 25 |
| 102 | Maria | Chi | 30 |
| 103 | Tor | Coz | 22 |
| 104 | Nat | Ive | 27 |
| 105 | Don | Sok | 35 |
例子2:按时间过滤
你想查出最近一小时内下的所有订单:
SELECT *
FROM orders
WHERE order_date >= NOW() - INTERVAL '1 hour';
注意INTERVAL(时间区间)用起来多方便。
例子3:按月份分组
你想统计今年每个月的订单数:
SELECT DATE_PART('month', order_date) AS order_month, COUNT(*) AS order_count
FROM orders
WHERE DATE_PART('year', order_date) = DATE_PART('year', CURRENT_DATE)
GROUP BY DATE_PART('month', order_date)
ORDER BY order_month;
这里按月份分组,结果也按月份排序。
结果示例:
| order_month | order_count |
|---|---|
| 1 | 120 |
| 2 | 95 |
| 3 | 134 |
| 4 | 110 |
| 5 | 42 |
例子4:提取星期几
你想知道哪天订单最多:
SELECT DATE_PART('dow', order_date) AS day_of_week, COUNT(*) AS order_count
FROM orders
GROUP BY DATE_PART('dow', order_date)
ORDER BY order_count DESC;
DATE_PART('dow')会返回每个订单的星期几,0是星期天,1是星期一,以此类推。DOW就是DayOfWeek(星期几)的缩写。
结果示例:
| day_of_week | order_count |
|---|---|
| 5 | 210 |
| 4 | 190 |
| 3 | 175 |
| 2 | 160 |
| 1 | 140 |
| 6 | 120 |
| 0 | 95 |
注意常见的坑
处理日期经常让人头大,容易踩坑。下面这些是你可能会遇到的常见问题:
日期和时间的格式:用NOW()或者其他返回日期时间的函数时,一定要注意它的格式。比如你要把order_date和CURRENT_DATE对比,记得忽略时间部分或者写清楚。
日期是字符串:有时候数据库里日期其实是字符串(比如text)。你要是直接用日期函数(比如DATE_PART()),肯定报错。一定要保证数据类型是DATE或者TIMESTAMP。
时区不一致:如果你的服务器和数据来源的时区不一样,很容易搞混。可以考虑用TIMESTAMPTZ类型。
GO TO FULL VERSION