每个总和都带有 WHERE 子句的 SUM 函数?

Posted

技术标签:

【中文标题】每个总和都带有 WHERE 子句的 SUM 函数?【英文标题】:SUM Function with WHERE clause for each sum? 【发布时间】:2020-10-30 18:02:38 【问题描述】:

我有两张桌子:StaffHours


员工(200 多行)与:

员工 ID、姓名、职位

每个员工在此表中只出现一次


小时数(1000 多行):

Staff_ID、小时、金额、BillableFlag、Office、DatePeriod

每个工作人员在此表中出现多次


我需要一个查询,该查询从 Staff 表中提取所有 Staff,其中 position = 'Assistant' 并且 Hours 表中的 Hours 和 Amount 列分别求和两次,每次求和的逻辑不同。

类似这样(这是一个带有一些简单英语的查询以帮助解释):

select s.name,
sum(h.hours) as 'Hours_Not_Billable' --[NEED IT TO SUM ONLY HOURS WHERE h.BILLABLEFLAG <> 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER],
sum(h.amount) as 'Amount_Not_Billable' --[NEED IT TO SUM ONLY AMOUNT WHERE h.BILLABLEFLAG <> 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER],
sum(h.hours) as 'Hours_Billable' --[NEED IT TO SUM ONLY HOURS WHERE h.BILLABLEFLAG = 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER],
sum(h.amount) as 'Amount_Billable --[NEED IT TO SUM ONLY HOURS WHERE h.BILLABLEFLAG = 'Y', h.office = '2', h.period = 'Q3' AND ONLY DO IT FOR EACH STAFF MEMBER]'
from Staff S 
left join Hours H on S.Staff_ID = H.Staff_ID

where s.position = 'Assistant'
group by s.name

非常感谢您的帮助!

谢谢

【问题讨论】:

尝试搜索[tsql] conditional aggregation。通过在每个 sum 中添加 case 表达式,您可以控制添加哪些值。 【参考方案1】:

使用条件聚合。这个想法是在sum() 中放置一个case 表达式,过滤掉的值会被考虑在内。

您的伪代码将翻译为:

select 
    s.name,
    sum(case when h.billableflag <> 'Y' then h.hours  else 0 end) hours_not_billable,
    sum(case when h.billableflag <> 'Y' then h.amount else 0 end) amount_not_billable,
    sum(case when h.billableflag =  'Y' then h.hours  else 0 end) hours_billable,
    sum(case when h.billableflag =  'Y' then h.amount else 0 end) amount_billable
from staff s 
left join hours h 
    on s.staff_id = h.staff_id and h.office = 2 and h.period = 'Q3'
where s.position = 'Assistant'
group by s.name

注意:大部分条件对所有表达式都是通用的,所以我将它们移到了left joinon 子句中。

【讨论】:

我认为最好将其他条件 (h.office = 2 and h.period = 'Q3') 移动到 WHERE 子句并使用索引列保留连接以获得更好的性能。你同意吗? @SaeedEsmaeelinejad:这不会做同样的事情。我们有一个left join:将条件放在where 子句中会将其转换为inner join【参考方案2】:

您可以在 SUM() 聚合函数中使用 CASE WHEN,如下所示

select 
s.name,
sum(case when h.BILLABLEFLAG <> 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.hours else null end) as 'Hours_Not_Billable', 
sum(case when h.BILLABLEFLAG <> 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.amount else null end) as 'Amount_Not_Billable', 
sum(case when h.BILLABLEFLAG = 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.hours else null end) as 'Hours_Billable',
sum(case when h.BILLABLEFLAG = 'Y' and h.office = '2' and h.DatePeriod = 'Q3' then h.amount else null end ) as 'Amount_Billable'
from Staff S 
left join Hours H on S.Staff_ID = H.Staff_ID
where s.position = 'Assistant'
group by s.name

【讨论】:

以上是关于每个总和都带有 WHERE 子句的 SUM 函数?的主要内容,如果未能解决你的问题,请参考以下文章

一个带有两个where子句的查询中的两个sql总和[重复]

mysql SUM() 在 WHERE 子句中

如何使用具有相同值的 OVER 子句的 SUM 函数按列返回正确的总和?

Oracle [过程] - Sum 函数忽略 WHERE 子句

带有 where 子句的窗口函数(LEAD/LAG)?

如何使用 where 子句获取 mysql 中选定行的总和?