#sql #sql-server #tsql #sum #pivot
#sql #sql-сервер #tsql #сумма #сводная
Вопрос:
У меня есть две таблицы: персонал и часы.
Штат (более 200 строк) с:
Staff_ID, имя, должность
каждый сотрудник появляется в этой таблице только один раз
Часы (более 1000 строк) с:
Staff_ID, часы, Сумма, оплачиваемый флаг, Офис, дата-период
каждый сотрудник появляется в этой таблице много раз
Мне нужен запрос, который извлекает весь персонал из таблицы Staff с position = ‘Assistant’, а столбцы Hours и Amount из таблицы Hours суммируются дважды, каждый с разной логикой для каждой суммы.
Что-то вроде этого (это запрос на простом английском языке, чтобы помочь с объяснением):
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
Помощь очень ценится!
Спасибо
Комментарии:
1. Попробуйте выполнить поиск
[tsql] conditional aggregation
.case
Вставляя выражение внутри каждогоsum
, вы можете контролировать, какие значения добавляются.
Ответ №1:
Используйте условную агрегацию. Идея состоит в том, чтобы поместить case
внутри выражение sum()
, которое отфильтровывается с учетом значений.
Ваш псевдокод будет переводиться как:
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
Примечание: большинство условий являются общими для всех выражений, поэтому я перенес их в on
предложение the left join
.
Комментарии:
1. Я думаю, что лучше переместить другое условие (
h.office = 2 and h.period = 'Q3'
) вWHERE
предложение и оставить соединение с индексированным столбцом для лучшей производительности. Вы согласны?2. @SaeedEsmaeelinejad: это не будет делать то же самое. У нас есть a
left join
: включение условий вwhere
предложение превратит его в aninner join
.
Ответ №2:
Вы можете использовать СЛУЧАЙ, когда внутри функции агрегирования SUM() следующим образом
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