题目描述

(通过次数12,487 | 提交次数28,952,通过率43.13%)

Employee 表保存了一年内的薪水信息。
请你编写 SQL 语句,对于每个员工,查询他除最近一个月(即最大月)之外,剩下每个月的近三个月的累计薪水(不足三个月也要计算)。
结果请按 Id 升序,然后按 Month 降序显示。

示例:
输入:
| Id | Month | Salary |
|----|-------|--------|
| 1  | 1     | 20     |
| 2  | 1     | 20     |
| 1  | 2     | 30     |
| 2  | 2     | 30     |
| 3  | 2     | 40     |
| 1  | 3     | 40     |
| 3  | 3     | 60     |
| 1  | 4     | 60     |
| 3  | 4     | 70     |
输出:

| Id | Month | Salary |
|----|-------|--------|
| 1  | 3     | 90     |
| 1  | 2     | 50     |
| 1  | 1     | 20     |
| 2  | 1     | 20     |
| 3  | 3     | 100    |
| 3  | 2     | 40     |

解释:
员工 '1'除去最近一个月(月份 '4'),有三个月的薪水记录:月份 '3'薪水为40,月份 '2'薪水为 30,月份 '1'薪水为 20。
所以近 3 个月的薪水累计分别为(40 + 30 + 20) =90,(30 + 20) = 50 和 20。

| Id | Month | Salary |
|----|-------|--------|
| 1  | 3     | 90     |
| 1  | 2     | 50     |
| 1  | 1     | 20     |
员工 '2' 除去最近的一个月(月份 '2')的话,只有月份 '1' 这一个月的薪水记录。
| Id | Month | Salary |
|----|-------|--------|
| 2  | 1     | 20     |
员工 '3' 除去最近一个月(月份 '4')后有两个月,分别为:月份 '3' 薪水为 60 和 月份 '2' 薪水为 40。所以各月的累计情况如下:
| Id | Month | Salary |
|----|-------|--------|
| 3  | 3     | 100    |
| 3  | 2     | 40     |

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-cumulative-salary-of-an-employee
//测试数据
Create table If Not Exists Employee (id int, month int, salary int);

insert into Employee (id, month, salary) values ('1', '1', '20');
insert into Employee (id, month, salary) values ('2', '1', '20');
insert into Employee (id, month, salary) values ('1', '2', '30');
insert into Employee (id, month, salary) values ('2', '2', '30');
insert into Employee (id, month, salary) values ('3', '2', '40');
insert into Employee (id, month, salary) values ('1', '3', '40');
insert into Employee (id, month, salary) values ('3', '3', '60');
insert into Employee (id, month, salary) values ('1', '4', '60');
insert into Employee (id, month, salary) values ('3', '4', '70');
insert into Employee (id, month, salary) values ('1', '7', '90');
insert into Employee (id, month, salary) values ('1', '8', '90');

解题思路

这是一道困难题,通过率只有43.13%。确实有些难度。但我觉得,难度并不体现在SQL有多难写,而是体现在细心程度上。就像我第一次提交失败,就是因为忘记做ORDER BY了。

题目要求,不计算每个id的最大月份的统计数据。那么可以先把这部分数据先过滤掉。再统计每个月份最近3个月的累计数据,最后排序返回即可。

取出最大月份并过滤,以及排序都比较容易实现。

难点主要在于如何统计每个月份最近3个月的累计数据。

对于累计数据的计算,一般来说,都可以通过自关联,然后限定合适的关联条件,再分组汇总来实现。

具体到统计最近3个月的数据。那么,可以把当月、上月、上上月的数据发散到当月来,再以当月来汇总统计实现。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
with
tmp as (
    select
        a.*
    from Employee a
    where (a.id,a.month) not in 
          (select id,max(month) from Employee group by id)
)
select
    a.id,a.month,sum(b.salary) Salary
from tmp a
inner join tmp b
on a.id = b.id
and b.month between a.month - 2 and a.month
group by a.id,a.month
order by a.id,a.month desc;
picture loss