Question

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

Was it helpful?

Solution

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)

OTHER TIPS

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top