日期运算与时间间隔
对时间段进行加减,并计算日期之间的差值。
日期运算与时间间隔 是 CoddyKit 上的免费 SQL Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Interview Prep 课程共包含 4 节课。
为什么日期运算常出现在面试中
日期运算是最实用的 SQL 技能之一,因此面试官经常在分析师和后端岗位的面试中重点考察它。几乎每个业务问题都包含时间因素:最近 30 天、每周订单数、注册后的天数。
问题在于,日期函数是 SQL 中标准化程度最低的部分。同一操作在 PostgreSQL、MySQL 和 SQL Server 中的语法各不相同。优秀的候选人会先清楚地说明思路,再根据具体方言调整语法。
- 添加或减去一段时间
- 计算两个日期之间的差值
- 使用
INTERVAL值
INTERVAL 类型
在 PostgreSQL 和 SQL 标准中,一段时间是名为时间间隔的一等值。您可以使用普通的 + 和 - 运算符,将它加到日期或时间戳上,或从中减去它。
这是表达“30 天前”或“从现在起 3 个月后”的最清晰方式。面试官也很喜欢这种写法,因为它读起来就像英语。
SELECT
CURRENT_DATE,
CURRENT_DATE + INTERVAL '7 days' AS next_week,
CURRENT_DATE - INTERVAL '1 month' AS last_month,
NOW() + INTERVAL '90 minutes' AS soon;跨数据库方言添加时间段
面试官经常会问:“在 MySQL 和 SQL Server 中,您分别会如何添加 7 天?”掌握这三种主流方言,说明您确实有实际经验。
- PostgreSQL:
d + INTERVAL '7 days' - MySQL:
DATE_ADD(d, INTERVAL 7 DAY) - SQL Server:
DATEADD(day, 7, d)
概念完全相同,只有写法不同。请始终说明您使用的是哪种方言。
-- MySQL
SELECT DATE_ADD(order_date, INTERVAL 7 DAY) AS due_date FROM orders;
-- SQL Server
SELECT DATEADD(day, 7, order_date) AS due_date FROM orders;两个日期之间的差值
日期运算的另一部分是计算两个日期相隔多远。结果取决于所使用的单位和数据库方言。
在 PostgreSQL 中,两个 date 值相减会直接得到一个表示天数的整数。而两个 timestamp 值相减则会得到一个时间间隔。
-- Postgres: date - date returns an integer (days)
SELECT shipped_date - order_date AS days_to_ship
FROM orders;DATEDIFF 及其陷阱
DATEDIFF 在 MySQL 和 SQL Server 中都存在,但行为不同,这是面试中很常见的陷阱。
- MySQL:
DATEDIFF(end, start)只返回完整的天数。 - SQL Server:
DATEDIFF(unit, start, end)接受一个单位,并计算跨越的边界,而不是完整的单位数。
这种边界行为很重要:在 SQL Server 中,DATEDIFF(year, '2023-12-31', '2024-01-01') 返回1,即使实际只过去了一天。
-- SQL Server: counts boundaries, not elapsed time
SELECT DATEDIFF(year, '2023-12-31', '2024-01-01'); -- 1
SELECT DATEDIFF(day, '2023-12-31', '2024-01-01'); -- 1正确计算年龄(按年)
“计算客户的年龄(按年)”是一道经典题。简单地用天数差除以 365 会因为闰年而产生偏差。PostgreSQL 提供了 AGE(),可以返回真正的日历时间间隔。
如果需要得到整数形式的年龄,请提取年龄中的年份部分。
-- Postgres
SELECT
birth_date,
AGE(CURRENT_DATE, birth_date) AS exact_age,
EXTRACT(YEAR FROM AGE(CURRENT_DATE, birth_date)) AS age_years
FROM customers;实例:最近 30 天内的订单
这是面试中几乎普遍会遇到的筛选条件。正确做法是将日期列与计算出的截止时间进行比较,而不是对该列套用函数。
将 order_date 与一个常量截止时间比较,可以继续使用 order_date 上的索引。稍后我们会再次讨论这一索引要点。
SELECT COUNT(*) AS recent_orders
FROM orders
WHERE order_date >= CURRENT_DATE - INTERVAL '30 days';日历月份的半开区间
当题目要求“2024 年 3 月的所有订单”时,不要在时间戳列上使用 BETWEEN '2024-03-01' AND '2024-03-31'。这样会漏掉 3 月 31 日晚上 11 点的行,而且容易产生边界错误。
稳健的模式是使用半开区间:大于或等于开始时间 >=,并小于下个月的开始时间 <。它适用于任何列精度。
SELECT *
FROM orders
WHERE order_ts >= DATE '2024-03-01'
AND order_ts < DATE '2024-04-01';EXTRACT 和日期部分
从日期中提取单个组成部分是报表工作中的常见需求。标准函数是 EXTRACT(part FROM d),PostgreSQL 和 MySQL 都支持它。
EXTRACT(YEAR FROM d)、MONTH、DAY- 使用
EXTRACT(DOW FROM d)获取星期几 - SQL Server 则使用
DATEPART(weekday, d)
请注意:仅提取 MONTH 会将不同年份的 3 月归到一起,这通常不是您想要的结果。
SELECT
EXTRACT(YEAR FROM order_ts) AS yr,
EXTRACT(MONTH FROM order_ts) AS mo,
COUNT(*) AS n
FROM orders
GROUP BY 1, 2
ORDER BY 1, 2;深入示例:距离下一个生日还有多少天
这是一道更有难度的日期运算题,结合了提取和加法。请根据出生月份和日期构建今年的生日;如果生日已经过去,则顺延到下一年。
口头说明这一过程,可以向面试官展示您能够处理诸如“今年的生日已经过了”这样的边界情况。
-- Postgres
SELECT
name,
CASE
WHEN MAKE_DATE(EXTRACT(YEAR FROM CURRENT_DATE)::int,
EXTRACT(MONTH FROM birth_date)::int,
EXTRACT(DAY FROM birth_date)::int) >= CURRENT_DATE
THEN MAKE_DATE(EXTRACT(YEAR FROM CURRENT_DATE)::int,
EXTRACT(MONTH FROM birth_date)::int,
EXTRACT(DAY FROM birth_date)::int) - CURRENT_DATE
ELSE MAKE_DATE(EXTRACT(YEAR FROM CURRENT_DATE)::int + 1,
EXTRACT(MONTH FROM birth_date)::int,
EXTRACT(DAY FROM birth_date)::int) - CURRENT_DATE
END AS days_until
FROM customers;月份的第一天和最后一天
“给出每个订单所在月份的最后一天”考察的是您会使用内置功能,还是会重新实现它。PostgreSQL 将 DATE_TRUNC 与时间间隔运算组合使用;MySQL 则直接提供了 LAST_DAY()。
在 PostgreSQL 中求月份最后一天的技巧是:先截断到月份的第一天,加上一个月,再减去一天。
-- Postgres
SELECT
DATE_TRUNC('month', order_ts) AS month_start,
DATE_TRUNC('month', order_ts) + INTERVAL '1 month - 1 day' AS month_end
FROM orders;
-- MySQL: LAST_DAY(order_ts)快速检查
请测试您对跨数据库方言的日期差值行为的理解。
回顾:日期运算和时间间隔
面试中的关键要点:
- 在 PostgreSQL 中使用
INTERVAL值和+/-;在 MySQL 中使用DATE_ADD/DATEDIFF;在 SQL Server 中使用DATEADD/DATEDIFF。 - SQL Server 的 DATEDIFF 计算跨越的边界,而不是经过的单位数,这是最常见的陷阱。
- 要按年计算年龄,请从
AGE()中提取年份,而不要用天数除以 365。 - 通过将列与计算出的截止时间比较来筛选最近的行,并对月份时间窗口使用半开区间(
>= start AND < next)。
先说明概念,再根据具体方言进行调整。
常见问题解答
「日期运算与时间间隔」课时是免费的吗?
是的 — 「日期运算与时间间隔」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 SQL Interview Prep 课程共包含 4 节课。
「日期运算与时间间隔」这节课中我会学到什么?
对时间段进行加减,并计算日期之间的差值。 你通过在浏览器中直接运行的动手代码来练习 SQL Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「日期运算与时间间隔」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Interview Prep 课中编写并运行代码吗?
能。每节 SQL Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 日期运算与时间间隔
- 截断日期与划分日期区间
- 解析与格式化字符串
- 时区与时间戳