1. Turn events into ranges:
ID EmployeeID Status EffectiveDate ID EmployeeID Status StartDate EndDate -- ---------- -------- ------------- -- ---------- -------- --------- --------- 1 110545 Active 01AUG2011 1 110545 Active 01AUG2011 01JUL2012 2 110700 Active 05JAN2012 2 110700 Active 05JAN2012 31DEC9999 3 110060 Active 05JAN2012 => 3 110060 Active 05JAN2012 31DEC9999 4 110222 Active 30JUN2012 4 110222 Active 30JUN2012 31DEC9999 5 110545 Resigned 01JUL2012 5 110545 Resigned 01JUL2012 12FEB2013 6 110545 Active 12FEB2013 6 110545 Active 12FEB2013 31DEC9999
2. Acquire active employees based on this condition:
WHERE Status = 'Active' AND StartDate < @EndDate AND EndDate > @StartDate
3. Consider Excellent EmployeeID Values.
Here's how you could implement the above:
WITH ranked AS ( SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY EffectiveDate) FROM EmployeeActivity ), ranges AS ( SELECT s.EmployeeID, s.Status, StartDate = s.EffectiveDate, EndDate = ISNULL(e.EffectiveDate, '31DEC9999') FROM ranked s LEFT JOIN ranked e ON s.EmployeeID = e.EmployeeID AND s.rn = e.rn - 1 ) SELECT ActiveCount = COUNT(DISTINCT EmployeeID) FROM ranges WHERE Status = 'Active' AND StartDate < '01JAN2013' AND EndDate > '01AUG2012' ;
Demo SQL Fiddle for this query: http://sqlfiddle.com/#!3/c3716/3
Andriy m
source share