通过聚合函数进行SQL过滤

时间:2014-10-15 19:26:32

标签: sql sql-server database tsql aggregates

假设我有一个Employee表和一个Department表。每个员工都有一个部门。

现在,假设我想看到所有部门 - 以及那些部门的员工 - ,只有1名员工。

假设我的数据库看起来像这样。

员工

EmployeeId  | EmployeeName  | DepartmentId
--------------------------------------------
1           | A Doe         | 1
--------------------------------------------
2           | B Doe         | 1
--------------------------------------------
3           | C Doe         | 1
--------------------------------------------
4           | D Doe         | 1
--------------------------------------------
5           | E Doe         | 2
--------------------------------------------

DepartmentId  | DepartmentName
------------------------------------------
1             | Sales   
------------------------------------------                    
2             | HR
------------------------------------------

我想看到的是以下结果:

DepartmentName  | EmployeeId  | EmployeeName  | EmployeeId_COUNT
------------------------------------------------------------------
HR              | NULL        | NULL          | 1
------------------------------------------------------------------
HR              | 5           | E Doe         | 1
------------------------------------------------------------------

显然,这可以通过多个单独的查询来完成。

但是,是否有人知道使用单个查询解决此问题的方法?

我最初的想法是做一些简单的事情,比如这个

SELECT 
        d.DepartmentName 'Department'
        , e.EmployeeId 'EmployeeId'
        , e.EmployeeName
        , COUNT(e.EmployeeId) 'EmployeeId_COUNT'

FROM    Employee e
        LEFT JOIN Department d ON d.DepartmentId = e.DepartmentId

GROUP BY  GROUPING SETS ( 
                ( d.DepartmentName ), 
                ( d.DepartmentName, e.EmployeeId, e.EmployeeName) )
HAVING COUNT(e.EmployeeId) IN (1)

但是这不起作用,因为每个不是分组行的行(以及一些分组的行)的EmployeeId计数为1。

因此,结果将如下所示:

DepartmentName  | EmployeeId  | EmployeeName  | EmployeeId_COUNT
------------------------------------------------------------------
HR              | NULL        | NULL          | 1
------------------------------------------------------------------
HR              | 5           | E Doe         | 1
------------------------------------------------------------------
Sales           | 1           | A Doe         | 1
------------------------------------------------------------------
Sales           | 2           | B Doe         | 1
------------------------------------------------------------------
Sales           | 3           | C Doe         | 1
------------------------------------------------------------------
Sales           | 4           | D Doe         | 1
------------------------------------------------------------------

这根本不是我想要的。

我理想的解决方案很简单(不需要复杂的内部查询,UNION或INTERSECT),并且很容易推广到类似的问题(SUM,MAX,MIN等以及更复杂查询中的其他列)。

我还应该注意我在T-SQL 2012中这样做,所以任何可能有用的特殊功能或命令都是合理的游戏

1 个答案:

答案 0 :(得分:1)

您可以COUNT()OVER()一起使用,以获取您之后的信息:

;with cte AS (SELECT *,COUNT(*) OVER(PARTITION BY DepartmentID) AS Department_CT
              FROM   Employee)
SELECT *
FROM cte a
JOIN  Department b
  ON a.DepartmentID = b.DepartmentID
WHERE Department_CT = 1

这允许您保留完整的详细信息以及返回聚合以进行过滤。