T-SQL聚合函数子查询

时间:2016-11-17 17:29:38

标签: sql-server tsql subquery aggregate-functions

我收到以下错误:

Cannot perform an aggregate function on an expression containing an aggregate or a subquery.

使用此代码:

SELECT 
    loc.Location
    ,COUNT(CASE 
        WHEN hr.SAC in (SELECT [SAC] FROM dbo.[Titles] WHERE [title] = 'XYZ')
            THEN 1 
            ELSE NULL 
        END) AS XYZ_Trainee_Count
    ,COUNT(CASE 
        WHEN hr.SAC in (SELECT [SAC] FROM dbo.[Titles] WHERE [title] = 'ABC')
            THEN 1 
            ELSE NULL 
        END) AS ABC_Trainee_Count

FROM
    dbo.n_HRODS hr INNER JOIN dbo.Locations loc
        ON loc.LocationID = hr.LocationID
    INNER JOIN dbo.EmpData dat
        ON dat.EmpID = hr.EmpID

WHERE dat.Trainee = 1

GROUP BY loc.Location

dbo。[标题]是一个视图,它结合了另外两个表中的两列。我基本上是这样做的,因为我之前的程序员做了类似这样的事情:

,COUNT(CASE 
    WHEN SAC in ( lists about 30 items)
        THEN 1 
        ELSE NULL 
    END) 

显然,我不想在该案例陈述中列出30个项目......当这些项目在3年内因任何原因发生变化时,那么谁会记得回到这段代码并更新这些项目?没有人...

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您可以使用LEFT OUTER JOINs表格的额外title来完成此操作:

SELECT 
    loc.Location
    ,COUNT(CASE WHEN titles1.[SAC] IS NOT NULL THEN 1 ELSE NULL END) AS XYZ_Trainee_Count
    ,COUNT(CASE WHEN titles2.[SAC] IS NOT NULL THEN 1 ELSE NULL END) AS ABC_Trainee_Count

FROM
    dbo.n_HRODS hr INNER JOIN dbo.Locations loc
        ON loc.LocationID = hr.LocationID
    INNER JOIN dbo.EmpData dat
        ON dat.EmpID = hr.EmpID
    LEFT OUTER JOIN dbo.[Titles] titles1
        ON titles1.[title]='XYZ' AND
            hr.SAC = titles1.[SAC]
    LEFT OUTER JOIN dbo.[Titles] titles2
        ON titles2.[title]='ABC' AND
            hr.sac = titles2.[SAC]    
WHERE dat.Trainee = 1    
GROUP BY loc.Location

或者,如果你真的与SELECT语句中的那些子查询结合,因为实际的查询是一个很大的噩梦,并且想要使用连接进行monkeying足以让你晕倒,那么你可以从这个查询中删除聚合并在聚合之前将其全部推入子查询:

SELECT location, count(XYZ_Trainee) AS XYZ_Trainee_Count, count(ABC_Trainee) as ABC_Trainee
FROM
(
    SELECT 
        loc.Location
        ,CASE 
            WHEN hr.SAC in (SELECT [SAC] FROM dbo.[Titles] WHERE [title] = 'XYZ')
                THEN 1 
                ELSE NULL 
            END AS XYZ_Trainee
        ,CASE 
            WHEN hr.SAC in (SELECT [SAC] FROM dbo.[Titles] WHERE [title] = 'ABC')
                THEN 1 
                ELSE NULL 
            END AS ABC_Trainee

    FROM
        dbo.n_HRODS hr INNER JOIN dbo.Locations loc
            ON loc.LocationID = hr.LocationID
        INNER JOIN dbo.EmpData dat
            ON dat.EmpID = hr.EmpID

    WHERE dat.Trainee = 1
) sub
GROUP BY location

我的目标是第一个解决方案,因为它将更容易维护,并且可能从您的RDBMS获得更好的执行路径并因此更快地运行。虽然......这只是猜测。

答案 1 :(得分:2)

非常类似于JNevill的第一个答案。但是如果你加入一次冠军头衔,你可以检查并计算你想要的任何数量的冠军。

SELECT 
    loc.Location
    ,COUNT(CASE WHEN t.[title] = 'XYZ' THEN 1 END) AS XYZ_Trainee_Count
    ,COUNT(CASE WHEN t.[title] = 'ABC' THEN 1 END) AS ABC_Trainee_Count

FROM
    dbo.[n_HRODS] hr 
INNER JOIN dbo.[Locations] loc
        ON loc.LocationID = hr.LocationID
INNER JOIN dbo.[EmpData] dat
        ON dat.EmpID = hr.EmpID
INNER JOIN dbo.[Titles] t
        ON  hr.SAC = t.[SAC]    
WHERE dat.Trainee = 1

GROUP BY loc.Location