Reputation: 25143
I have a time table for a school in the tables. Also I know startDate and endDate of the school. The table structure is like this:
SubjectsToDay
Subject | Day
---------------------
Maths | Monday
Physics | Tuesday
Chemistry| Wednesday
Maths | Thursday
Biology | Friday
Holidays
Date | Reason
----------------------------
2014-01-26 | Republic day
2014-05-01 | Labour's day
2014-06-04 | Reason1
2014-07-04 | Reason2
2014-07-14 | Reason3
2014-08-14 | Reason4
2014-09-14 | Reason5
2014-10-12 | Reason6
I want to calculate number of working days for a particular subject(input, lets say Maths).
The working days should not consider holidays given in Holidays
table. I want to do this in Stored procedure which takes StartDate, EndDate and Subject as parameter. How can I right this in efficient way?
P.S.- Holiday table is not fixed, any rows can be added or deleted from this
Upvotes: 0
Views: 161
Reputation: 4103
use a cte to get all the dates, join with the subjects to count the number of lessons and join with the holidays to exclude them:
declare @startdate date;
set @startdate = '2014-01-01';
declare @enddate date;
set @enddate = '2014-12-31'
;with DateRange AS
(
SELECT
@startdate as DateValue
UNION ALL
SELECT
dateadd(dd,1,DateValue)
FROM DateRange
WHERE dateadd(dd,1,DateValue) <= @enddate
)
select
s.Name
, COUNT(*)
from DateRange d
join SubjectsToDay s
on DATENAME(dw,d.DateValue) = s.Day
left outer join
Holidays h
on d.DateValue = h.Date
where h.Reason is null
group by
s.Name
option (maxrecursion 365)
Upvotes: 1
Reputation: 44336
Most people would use a calendar table for this, but here is a calculation that should give the same result. I suggest you put it into a stored procedure, after merging it with your environment.
-- your parameters
DECLARE @from date = '2014-01-01', @to date = '2014-01-01'
DECLARE @Subjectname varchar(15) = 'Chemistry'
-- variable declarations
DECLARE @d int
DECLARE @holiday TABLE(Date date, Reason varchar(20))
DECLARE @subject TABLE(Name varchar(15), Day varchar(10))
-- mapping day to numeric value
;WITH x as
(
SELECT CASE Day WHEN 'Monday' THEN 2
WHEN 'Tuesday' THEN 3
WHEN 'Wednesday' THEN 4
WHEN 'Thursday' THEN 5
WHEN 'Friday' THEN 6
-- allowing weekends for solving similar questions
WHEN 'Saturday' THEN 7
WHEN 'Sunday' THEN 1 END daynumber
FROM SubjectsToDay
WHERE Subject = @Subjectname
)
SELECT
-- number of chosen days between from and to
-- subtract holidays from same day between from and to
SUM(datediff(week, dateadd(d, -daynumber, @from),
dateadd(d, 1-daynumber, @to))
-y.cnt)
FROM X
CROSS APPLY
( SELECT count(*) cnt FROM Holidays WHERE datediff(d, -1, Date ) %7 + 1 = daynumber
AND Date between @from and @to) y
Upvotes: 0