Reputation: 1574
Code to get the test data:
create table SalesCalls
(
EmpId INT NOT NULL,
EmpName nvarchar(20),
month INT,
Year INT,
CallsMade INT
)
GO
Insert into SalesCalls values
(1,'ABC',12,2018,10),
(1,'ABC',1,2019,15),
(1,'ABC',2,2019,20),
(2,'DEF',12,2018,12),
(2,'DEF',1,2019,14),
(2,'DEF',2,2019,26)
GO
The objective is to compare the current month sales of an Employee with the previous month sales of that Employee and find out the percentage change in it. Achieved that using the below query:
With SalesCTE as
(
select EmpId,EmpName,
Month As CurrentMonth,
Year as CurrentMonthYear,
Case When month = 1 then 12 Else (Month-1) End AS PrevMonth,
Case when month = 1 then (Year - 1) Else Year End As PrevMonthYear,
CallsMade
from SalesCalls
)
select
S1.EmpId, S1.EmpName, S1.CurrentMonth, S1.CurrentMonthYear, S1.CallsMade as CurrentMonthCalls,
S2.CurrentMonth as PrevMont,
S2.CurrentMonthYear as PrevMonthYear,
S2.CallsMade as PrevMonthCalls,
( CONVERT(numeric(5,2),S1.CallsMade) / S2.CallsMade) * 100 As PercentageChange
from SalesCTE S1
JOIN SalesCTE S2 ON S1.EmpId = S2.EmpId
AND S1.PrevMonth = S2.CurrentMonth
AND S1.PrevMonthYear = S2.CurrentMonthYear
ORDER BY S1.EmpId, S1.CurrentMonth, S1.CurrentMonthYear
The above query worked until the time there are no redundant records for an Employee for the same month.
But later data from multiple sources is coming in and an Employee table can have multiple records for the same month and it is still valid. Because the employee could be making calls in different ways. An as example the below record is inserted into the table:
Insert into SalesCalls values
(1,'ABC',1,2019,1)
Now the above query which worked fine above for the comparison of current month SalesCalls with the previous month is no longer working.
Phase 2 of the use case: So to fix this I have build an intermediate temp table that contains aggregate data. The query used is:
Select EmpId, EmpName, month, Year, SUM(CallsMade) as CallsMade
into #SalesCalls
from SalesCalls
group by EmpId, EmpName, month, Year
Now the SalesCalls
table inside the CTE is replaced with #SalesCalls
and then the above query works fine.
But this #SalesCalls
table needs to be dropped and recreated every time to see the latest comparison data.
The question is, is it possible to get the comparison data using a single query only and no intermediate temp tables or views.
Upvotes: 1
Views: 6538
Reputation: 1271181
Just use window functions:
select EmpId, EmpName, month, Year,
sum(CallsMade) as CallsMade,
(case when lag(year * 12 + month) over (partition by empId order by year, month) = year * 12 + month - 1
then lag(sum(callsMade)) over (partition by empId order by year, month)
end) as prevMonthCalls,
(case when lag(year * 12 + month) over (partition by empId order by year, month) = year * 12 + month - 1
then callsMade * 100.0 / lag(sum(callsMade) over (partition by empId order by year, month)
end) as as perentageChange
from SalesCalls
group by EmpId, EmpName, month, Year;
No join
s, CTEs, subqueries, or temporary tables are needed at all.
Upvotes: 2
Reputation: 1574
One of the simplest solutions :
select EmpId, EmpName, month, Year,
sum(CallsMade) as CallsMade,
lag(sum(callsMade)) over (partition by empId order by year, month) AS prevMonthCalls,
sum(CallsMade) * 100.0 / lag(sum(CallsMade)) over (partition by empId order by year, month) as PercentageChange
from SalesCalls
group by EmpId, EmpName, month, Year
order by EmpId, Year,month;
Upvotes: 0