【问题标题】:MySQL - Exclude Most Recent Month by GroupMySQL - 按组排除最近一个月
【发布时间】:2017-05-14 21:53:14
【问题描述】:

问题:

Employee表保存了一年的工资信息。

编写一个 SQL 以获取员工在 3 个月内的工资累计总和,但不包括最近一个月。

结果应该按'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     |

我的代码:

SELECT t1.Id, t1.Month, 
  (SELECT SUM(Salary) 
   FROM  Employee AS t2
   WHERE t1.Id = t2.Id
   AND   t1.Month >= t2.Month) AS Salary
FROM Employee t1
WHERE Month <> (SELECT 
            MAX(Month) 
            FROM Employee
            GROUP BY t1.Id)
ORDER BY Id, Month DESC; 

我的输出:

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

预期:

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

我使用 MAX()GROUP BY() 函数来排除每个组的最近一个月,但它不适用于 Id=2。

关于如何摆脱下一行有什么建议吗?

| 2  | 2     | 50     |

提前致谢。

【问题讨论】:

  • 我删除了不兼容的数据库标签。请仅使用您正在使用的数据库进行标记。
  • 为什么month = 4 行被排除在结果之外?
  • @vkp 因为问题想排除每个员工 ID 的最近几个月。对于 Id = 1, 3,最近的 month = 4,但对于 Id = 2,最近的 month = 2 .

标签: mysql sql group-by subquery


【解决方案1】:

要仅获取最近 3 个月的累计总和,不包括每个 id 的最近一个月,您可以使用

SELECT t1.Id, t1.Month, SUM(t2.Salary) 
FROM Employee t1
JOIN Employee t2 ON t1.Id = t2.Id AND t1.Month - t2.Month <= 2 AND t1.Month - t2.Month >= 0
JOIN (SELECT id, MAX(month) as max_mth from Employee GROUP BY id) tmax on tmax.id=t1.id AND tmax.max_mth<>t1.month
GROUP BY t1.Id, t1.Month
ORDER BY t1.Id, t1.Month DESC; 

【讨论】:

  • 很好地阅读了完整的问题,包括大约 3 个月的部分。
  • 感谢您的帮助。但是您能否再解释一下 - 为什么我的原始代码不起作用?我从未在 JOIN 子句中使用过 AND - 不确定是否有参考站点?
  • @YunZhou 我相信根本问题是您的“GROUP BY t1.Id”行并没有真正做任何事情,因为它是在嵌套子查询之外定义的属性。但是,它不会抛出错误,因为 t1.id 对于给定的子查询是常量。
  • @YunZhou - 请参阅我的第二个答案。我认为您在原始帖子中实际上非常接近。
【解决方案2】:

试试这个:

SELECT t1.id, t1.month,
    (SELECT SUM(salary)
       FROM employee t2
      WHERE t1.id = t2.id
        AND t1.month >= t2.month
        AND t1.month - t2.month < 3) AS salary
  FROM (
    SELECT * FROM employee p
     WHERE month <> (select MAX(month)
      FROM employee c where c.id = p.id)) t1
ORDER BY id, month desc;

输出是:

+------+-------+--------+
| id   | month | salary |
+------+-------+--------+
|    1 |     3 |     90 |
|    1 |     2 |     50 |
|    1 |     1 |     20 |
|    2 |     1 |     20 |
|    3 |     3 |    100 |
|    3 |     2 |     40 |
+------+-------+--------+

您遇到的问题是,您只删除了所有员工上个月的数据。我相信你想要的是删除每个员工上个月的礼物,即使上个月是几个月前。此解决方案创建一个派生表,其中缺少每个员工的上个月,并使用该表代替您的 t1 员工表。

【讨论】:

  • 更新为将总和限制为 3 个月。
【解决方案3】:

我认为这个答案最接近您在原始查询中尝试做的事情:

SELECT t1.id, t1.month,
    (SELECT SUM(salary)
       FROM employee t2
      WHERE t1.id = t2.id
        AND t1.month >= t2.month
        AND t1.month - t2.month < 3) AS salary
  FROM employee t1
 WHERE month <> (SELECT MAX(month)
                   FROM employee t3
                  WHERE t3.id = t1.id)
 ORDER by id, month desc;

再看一眼,你实际上非常接近。我认为问题在于“GROUP BY t1.Id”行实际上并没有对任何内容进行分组,因为 t1.Id 对于任何给定的子查询都是常量,因为“t1”是在最外面的 select 语句中定义的。将其替换为 where 子句,并将 SUM() 查询中的总和限制为 3 个月,就可以了。

【讨论】:

  • 帮助很大!我猜 WHERE 子句有时可以作为 GROUP BY 工作,这与本例中 SELECT 语句中的子查询的想法相同。跨度>
【解决方案4】:

试试这个查询:

SELECT e.Id, e.Month, SUM( e2.Salary ) AS 'Salary'

FROM 
    Employee AS e

    INNER JOIN Employee AS e2
        ON e2.Id = e.Id
        AND e2.Month <= e.Month

WHERE 
    e.Month <> ( SELECT MAX( [Month] ) FROM Employee WHERE Id = e.Id )

GROUP BY
    e.Id, e.Month

ORDER BY 
    e.Id, e.Month DESC

输出是:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-22
    • 2022-11-22
    • 2016-01-31
    • 1970-01-01
    • 2012-01-25
    • 2022-11-10
    • 1970-01-01
    • 2017-08-06
    相关资源
    最近更新 更多