给定每日销售额,编写 SQL 计算 2025 年每天的 GMV,并计算截止到当天(年初至今)的累计销售额
面试题:2025年每日销售额及年初至今(YTD)累计销售额计算
1. 题目背景与要求
在电商和零售行业中,实时监控每日 GMV(商品交易总额)以及当年的累计销售额(Year-to-Date, 简称 YTD)是运营和财务部门最核心的数据需求之一。
请编写 SQL,基于给定的每日销售明细表,计算 2025 年每天的 GMV,以及截止到当天(2025年初至当天)的累计销售额。
2. 示例数据
输入表:sales_records(每日销售明细表)
| sales_date (销售日期) | sales_amount (销售金额) |
|---|---|
| 2024-12-31 | 5000.00 |
| 2025-01-01 | 10000.00 |
| 2025-01-02 | 15000.00 |
| 2025-01-03 | 12000.00 |
| 2025-01-04 | 20000.00 |
| 2025-01-05 | 18000.00 |
| 2025-02-01 | 25000.00 |
期望输出结果:
| sales_date | daily_gmv | ytd_gmv (2025年初至今累计) |
|---|---|---|
| 2025-01-01 | 10000.00 | 10000.00 |
| 2025-01-02 | 15000.00 | 25000.00 |
| 2025-01-03 | 12000.00 | 37000.00 |
| 2025-01-04 | 20000.00 | 57000.00 |
| 2025-01-05 | 18000.00 | 75000.00 |
| 2025-02-01 | 25000.00 | 100000.00 |
注:2024-12-31 的数据不应参与 2025 年的累计计算。
3. SQL 解答
sql
SELECT
sales_date,
sales_amount AS daily_gmv,
SUM(sales_amount) OVER (
ORDER BY sales_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS ytd_gmv
FROM
sales_records
WHERE
sales_date >= '2025-01-01'
AND sales_date <= '2025-12-31'
ORDER BY
sales_date;
4. 深度解析与面试应对指南
在面试中,这道题表面上考察的是窗口函数,但面试官更看重候选人对执行顺序、性能优化和边界条件的理解。
核心考点一:窗口函数 SUM() OVER () 的使用
- 计算累计值:累计计算(Running Total / Cumulative Sum)的标准解法是使用窗口函数。
- 语法拆解:
ORDER BY sales_date:指定按照日期先后顺序进行累加。ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:明确定义窗口范围为从第一行(起点)到当前行。- 面试官可能会问:如果不写
ROWS BETWEEN...会怎么样?- 解答:如果不写,默认的窗口范围是
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。在有重复日期的极端情况下,RANGE会把相同日期的值加和后再计算,而ROWS则是逐行计算。明确写出ROWS执行效率更高,且逻辑更严谨。
- 解答:如果不写,默认的窗口范围是
核心考点二:过滤条件(WHERE)与窗口函数的执行顺序
这是本题最容易出错的地方。SQL 的执行顺序是:FROM -> WHERE -> SELECT (及窗口函数) -> ORDER BY。
- 如果我们先在
WHERE中过滤了sales_date >= '2025-01-01',那么进入窗口函数的数据只包含 2025 年及以后的数据。 - 因此,
UNBOUNDED PRECEDING(起点)自然变成了 2025-01-01,完美实现了“年初至今(YTD)”的累计,而不会把 2024 年的 5000.00 元算进来。 - 避坑指南:千万不要使用子查询先算全局累计再用 WHERE 过滤日期,那样会导致 2025 年的数据包含了 2024 年的底数,不符合 “YTD(年初至今)” 的定义。
核心考点三:性能优化(Index 索引)
如果面试官追问:“如果这个表有几千万行数据,如何优化这个查询?”
- 索引优化:确保在
sales_date列上有索引。 - 范围查询优势:在 WHERE 子句中,我们使用了
sales_date >= '2025-01-01' AND sales_date <= '2025-12-31',这种范围写法(Range Query)可以直接利用索引快速定位数据。 - 反面教材:避免写成
WHERE YEAR(sales_date) = 2025。因为对索引列使用函数(如YEAR())会导致索引失效,触发全表扫描。