SUM使用CASE WHEN SELECT

时间:2016-09-30 19:15:29

标签: sql tsql

如何重新编写此查询,以便它不会触发以下错误:

"无法对包含聚合或子查询的表达式执行聚合函数。"

SELECT
    employees.loc_id
    ,SUM(CASE 
            WHEN 
                pos IN (SELECT DISTINCT pos FROM lookup WHERE lbl='Staff') 
            AND 
                loc IN (SELECT DISTINCT loc FROM lookup WHERE lbl='Staff')
            THEN 1
            ELSE 0 
        END) AS 'Staff Site 1'
    ,SUM(CASE 
            WHEN 
                pos IN (SELECT DISTINCT pos FROM table WHERE lbl='Staff') 
            AND 
                loc IN (SELECT DISTINCT loc FROM table WHERE lbl='Staff')
            THEN 1
            ELSE 0 
        END) AS 'Staff Site 2'

FROM table GROUP BY table.key_id ORDER BY key_id

显然我不能在SELECT内添加SUM声明?我怎样才能确保我只针对上述代码中描述的情况求和?

pos确定位置的类型。 loc确定在哪个站点(位置)。查找表的结构如下:

pos  | loc  | lbl
123  | XYZ  | Staff Site 1
456  | XYZ  | Staff Site 1
987  | XYZ  | Supervisor Site 1
123  | ABC  | Staff Site 2
123  | JKL  | Staff Site 3
123  | OPQ  | Staff Site 4
456  | OPQ  | Staff Site 4
345  | OPQ  | Staff Site 4

此查找表仅确定与特定位置的位置关联的标签。

有一个员工表,每个员工都被分配了一个pos#。

所以我希望我的查询从employee表中选择所有loc_id(位置id),并且对于每个loc_id,对查找表中的每个相应条目求和

因此,如果我有30名员工loc_id=XYZpos=123和20名员工loc_id=XYZpos=456,则输出

loc_id | Staff Site 1
XYZ    | 50

提前致谢,我希望这不会太令人困惑......

5 个答案:

答案 0 :(得分:4)

没有进入能够在聚合函数内部进行SELECT的技术。让我们退后一步,重新考虑您的查询。您正试图通过聚合Lookup表来解决它,但聚合实际上在Employee表上,并且来自查找表的连接。

您似乎也在尝试进行条件聚合以PIVOT结果。但是,无论哪种情况,如果您执行以下操作,您将获得指定的结果,如果您执行以下操作:

SELECT
    l.loc
    ,COUNT(DISTINCT e.Id) as EmployeesAtStaffSite1
FROM
    Lookup l
    INNER JOIN Employees e
    ON e.loc = l.loc
    AND e.pos = l.pos
WHERE
    l.lbl = 'Staff Site 1'
GROUP BY
    l.loc

另请注意,如果您将INNER JOIN更改为LEFT JOIN,那么对于员工站点1的任何未分配员工的位置,您可以获得0计数。

答案 1 :(得分:1)

外部查询引用表名table,但SELECT列表中的列使用employees.限定。查询执行GROUP BY table.key_id,但SELECT列表中返回的列名为loc_id。这两个子查询都在查找lbl与文字' Staff'匹配,这是第一个名为lookup的查找表。我们在lookup表中没有看到任何示例行,其中该条件将评估为true。在第二个集合中,子查询引用了另一个表(不幸名为)table

很难说出你实际上想要通过该查询完成什么。

令人困惑的是,问题的最后一部分表明您希望结果集具有两列,即employee表中的loc_id的不同值。还有某种聚合列包含满足某些条件的行数......

 loc_id  Staff Site 1
 ------  ------------ 
 XYZ               50  

让我们备份几步。

看起来您想要查看employee表中的所有行,而您只关注表中的三列或四列。这是您要分析的行和列集。 (目前尚不清楚是否需要从lbl表中引用名为table的列。一组引用table而不是lookup的子查询让它看起来就是这样。

因此,从您希望查询查看的行集开始......

 SELECT e.loc_id
      , e.pos
      , e.loc
   FROM employee e

由此,您希望获得loc_id的不同值。您将通过添加GROUP BY子句来实现这一目标。

我们很容易得到一个"计数"使用聚合loc_id与每个COUNT(*)相关的员工中的所有行。但是你有兴趣只计算符合特定标准的员工......有条件的聚合。

如果(loc_id,pos)的组合在查找表中是UNIQUE。 (示例数据使其看起来像是,但我们无法通过有限示例数据中的反例来确定...)

如果它是唯一的,我们可以对该表执行JOIN操作,以及#34;查找"与每位员工lbl相关联的(loc_id,pos)

 SELECT e.loc_id
      , e.pos
      , e.loc
      , l.lbl
   FROM employee e
   LEFT
   JOIN lookup l
     ON l.loc_id = e.loc_id
    AND l.pos    = e.pos

如果我想计算某个位置的员工人数与lookuplbl值为Staff Site 1的行相关联,我倾向于写一下如...

 SELECT e.loc_id
      , SUM(CASE WHEN l.lbl = 'Staff Site 1' THEN 1 ELSE 0 END) AS [Staff Site 1]
   FROM employee e
   LEFT
   JOIN lookup l
     ON l.loc_id = e.loc_id
    AND l.pos    = e.pos
  GROUP BY e.loc_id
  ORDER BY e.loc_id

如果我想要第二列,那么计算一下'员工网站2'

 SELECT e.loc_id
      , SUM(CASE WHEN l.lbl = 'Staff Site 1' THEN 1 ELSE 0 END) AS [Staff Site 1]
      , SUM(CASE WHEN l.lbl = 'Staff Site 2' THEN 1 ELSE 0 END) AS [Staff Site 2]
   FROM employee e
   LEFT
   JOIN lookup l
     ON l.loc_id = e.loc_id
    AND l.pos    = e.pos
  GROUP BY e.loc_id
  ORDER BY e.loc_id

如果我没有特定需要" pivot"结果,我可以更简单地为给定lbl的每employeeloc_id的每个值运行一个返回单独行的查询。

 SELECT e.loc_id  AS loc_id
      , e.lbl     AS lbl 
      , SUM(1)    AS cnt
   FROM employee e
   LEFT
   JOIN lookup l
     ON l.loc_id = e.loc_id
    AND l.pos    = e.pos
  GROUP BY e.loc_id
  ORDER BY e.loc_id

答案 2 :(得分:0)

执行此操作的一种方法(假设您确实需要这样做)是将聚合放在外部查询中,包含条件内容(即子查询),如下所示:

select key_id, sum(staff_site_1) as staff_site_1, , sum(staff_site_2) as staff_site_2
from (
    SELECT
    employees.key_id
    ,CASE 
        WHEN 
            pos IN (SELECT DISTINCT pos FROM lookup WHERE lbl='Staff') 
        AND 
            loc IN (SELECT DISTINCT loc FROM lookup WHERE lbl='Staff')
        THEN 1
        ELSE 0 
    END AS staff_site_1
    ,CASE 
        WHEN 
            pos IN (SELECT DISTINCT pos FROM lookup WHERE lbl='Staff') 
        AND 
            loc IN (SELECT DISTINCT loc FROM lookup WHERE lbl='Staff')
        THEN 1
        ELSE 0 
    END AS staff_site_2
    FROM table 
) x
GROUP BY key_id 
ORDER BY key_id

答案 3 :(得分:0)

; with _CTE as (
SELECT
    employees.loc_id
    ,CASE 
            WHEN 
                pos IN (SELECT DISTINCT pos FROM lookup WHERE lbl='Staff') 
            AND 
                loc IN (SELECT DISTINCT loc FROM lookup WHERE lbl='Staff')
            THEN 1
            ELSE 0 
        END AS StaffSite1
    ,CASE 
            WHEN 
                pos IN (SELECT DISTINCT pos FROM table WHERE lbl='Staff') 
            AND 
                loc IN (SELECT DISTINCT loc FROM table WHERE lbl='Staff')
            THEN 1
            ELSE 0 
        END AS StaffSite2

FROM table
)
SELECT
    loc_id
    ,SUM(StaffSite1) AS 'Staff Site 1'
    ,SUM(StaffSite2) AS 'Staff Site 2'

FROM _CTE GROUP BY loc_id ORDER BY loc_id

说明: _CTE是临时结果集,此处将CASE条件应用于数据。然后,您将在此结果集上运行聚合函数。

答案 4 :(得分:0)

我没有看到你在employees.loc_id的任何地方,但它在选择中。相反,您只有GROUP BY table.key_id ORDER BY key_id