如何在聚合后向SELECT查询添加其他列而不将它们包含在GROUP BY中?

时间:2016-11-11 12:47:48

标签: sql sql-server tsql greatest-n-per-group

这是我要查询的表格:

EmployeeId, Salary, Date
8, 500, 2016-11-02
8, 500, 2016-09-21
8, 500, 2016-10-18
9, 500, 2016-10-18
9, 500, 2016-09-21
9, 500, 2016-11-02
10, 1000, 2016-11-02
10, 700, 2016-09-21

我想选择一份员工名单,以及他们在该特定员工的最新日期工资。在样本数据的情况下,这是相同的日期(11-02),但不一定是这种情况。我的问题:

SELECT EmployeeId, Salary, MAX(Date)
FROM table
GROUP BY EmployeeId. Salary
ORDER BY EmployeeId

返回:

8, 500, 2016-11-02
9, 500, 2016-11-02
10, 700, 2016-09-21
10, 1000, 2016-11-02

我的预期输出是:

8, 500, 2016-11-02
9, 500, 2016-11-02
10, 1000, 2016-11-02

如果我在没有工资的情况下聚合,那么我会得到预期的结果,但我需要工资可见。有没有办法在聚合后包含它?

4 个答案:

答案 0 :(得分:3)

在窗口函数之前(因为并非所有RDBMS版本都支持它们),您可以使用内联视图执行此操作。

首先考虑您的需求:

  • 您需要一个由员工的最大日期和员工ID组成的数据集。
  • 您需要从表格中获取原始数据,而这些数据是您无法通过分组获得的......

要实现第一个,我们会生成内联视图(别名" B"下面)。 然后我们加入到基集以检索其他所需信息;允许内连接消除不需要的记录;并完全否定对外部查询的需要。

SELECT A.EmployeeId, A.Salary, A.Date
FROM table A
INNER JOIN (SELECT max(date) mDate, EmployeeID 
            FROM table
            GROUP BY EmployeeID) B
  on A.EmployeeID = B.EmployeeID
 and A.Date = B.MDate
ORDER BY EmployeeId

使用RDBMS时,可以根据集合来考虑数据,以及如何过滤这些集合并将它们连接在一起以实现所需的结果。对大多数(并非所有)RDBMS活动进行基于集合的处理将是最有效的。随着窗函数(Aka Analytical Functions)的引入,几代集可以在没有子查询的情况下完成;使它们成为数据分析的强大功能;虽然最初很难理解你的想法。

那么:ROW_NUMBER() OVER (PARTITION BY EmployeeId ORDER BY Date DESC) RN究竟做了什么?

它按照日期降序的顺序为每个新员工遇到(分区)分配一个从1开始的行号(因此每个员工的最新日期将始终具有1的RN!)但是,1 isn'由于SQL操作顺序生成选择值LAST(因此where子句已经执行),因此可以在where子句中查询。这意味着要使窗口函数达到所需的结果并通过RN = 1限制,您必须将其包装在子查询中,然后您可以访问RN = 1,从而仅返回具有最新日期的员工的记录。由于RDBMS能够独立于分析函数执行表的生成,因此它可以同时处理它们并且非常快速地提供响应。

答案 1 :(得分:2)

您可以使用窗口功能选择最新的:

with cte as (
    select EmployeeId, 
        Salary,
        Date
        ROW_NUMBER() OVER (PARTITION BY EmployeeId ORDER BY Date DESC) RN
    from [table]
)
select EmployeeId, 
    Salary,
    Date
from cte
where RN = 1

如果不清楚,您基本上是通过EmployeeId“分区”,按日期降序对每个分区内的行进行编号,然后选择此数字为1的行(即每个员工的最新行)。

答案 2 :(得分:1)

您可以使用窗口函数Row_Number()来查看最后一个值

Select * 
 From ( 
        Select *,RN = Row_Number() over (Partition By EmployeeId Order by Date Desc)
         From  YourTable
      ) A
 Where RN=1

答案 3 :(得分:1)

我倾向于使用APPLY执行这些操作。

SELECT t1.EmployeeId, t2.Salary, t2.Date
FROM table t1
CROSS APPLY (SELECT TOP 1 Salary, Date
             FROM table
             WHERE EmployeeId = t1.EmployeeId
             ORDER BY Date DESC) t2
ORDER BY t1.EmployeeId