Jafrul Sadek Nabil
Jafrul Sadek Nabil

Reputation: 85

Find employee shift by date name between date range

I have three table which are following,

Table HrShift :

Id  ShiftName       DaysOfWeek                                          StartTime   EndTime     StartDate   EndDate
1   Day Shift-1     Sunday,Monday,Tuesday,Wednesday,Thursday,Friday     09:00 AM    06:00 PM    2016-01-01  NULL
2   Day Shift-2     Sunday,Monday,Tuesday,Wednesday,Thursday,Friday     10:00 AM    07:00 PM    2010-01-01  NULL
3   Day Shift-3     Sunday,Monday,Tuesday,Wednesday,Thursday,Friday     11:00 AM    08:00 PM    2010-01-01  NULL

Table ShiftType :

Id  Name
1   Primary
2   Roster

Table EmployeeShifts :

Id  EmpId   HrShiftId   ShiftTypeId     StartDate   EndDate 
1   1       1           1               2018-01-01  NULL    
2   1       2           2               2018-02-01  2018-02-01
3   2       1           1               2018-01-01  NULL
4   2       2           2               2018-02-01  2018-02-01
5   2       3           2               2018-02-01  2018-02-01

Create table commands :

CREATE TABLE [HrShifts](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ShiftName] [nvarchar](max) NULL,
    [DaysOfWeek] [nvarchar](max) NULL,
    [StartTime] [nvarchar](max) NULL,
    [EndTime] [nvarchar](max) NULL,
    [StartDate] [datetime] NOT NULL,
    [EndDate] [datetime] NULL);

CREATE TABLE [ShiftType](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](max) NULL);

CREATE TABLE [EmployeeShifts](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [EmpId] [int] NOT NULL,
    [HrShiftId] [int] NOT NULL,
    [ShiftTypeId] [int] NOT NULL,
    [StartDate] [datetime] NOT NULL,
    [EndDate] [datetime] NULL);

I need to find single assigned shift for each employee between two dates. ShiftType Roster will get the priority over Primary. Need to check DaysOfWeek column in HrShift table which have to match by the day name for the date.

Expected Outcome between (2018-01-31 and 2018-2-2) is following

Date        EmpId   ShiftType   HrShiftId   ShiftName       StartTime   EndTime
2018-01-31  1       1           1           Day Shift-1     09:00 AM    06:00 PM
2018-02-01  1       2           2           Day Shift-2     10:00 AM    07:00 PM
2018-02-02  1       1           1           Day Shift-1     09:00 AM    06:00 PM
2018-01-31  2       1           1           Day Shift-1     09:00 AM    06:00 PM
2018-02-01  2       2           2           Day Shift-2     10:00 AM    07:00 PM
2018-02-02  2       2           3           Day Shift-3     11:00 AM    08:00 PM

Upvotes: 1

Views: 637

Answers (2)

Gordon Linoff
Gordon Linoff

Reputation: 1270553

First, you need to generate the days. For this you can use a recursive CTE (or calendar table) or similar method.

with days as (
      select convert(date, '2018-01-31') as dte
      union all
      select dateadd(day, 1, dte)
      from days
      where dte < '2018-02-02'
     )
select d.dte, es.*, hs.startTime, hs.endTime
from EmployeeShifts es join
     HrShift hs
     on es.HrShiftId = hs.id cross join
     days d
where d.dte >= hs.startDate and
      (d.dte < hs.endDate or hs.endDate is null) and
      hs.daysofweek like '%' + datename(weekday, d.dte) + '%';

I think the where clause covers all the matching logic that you want between the date and the schedules.

Upvotes: 1

abdul qayyum
abdul qayyum

Reputation: 555

I have changed few data values to show you different results: change temp variable names with yours.

here I make list of dates first @S_Date and @E_Date are inputs:

    DECLARE @S_Date AS DATETIME
    DECLARE @E_Date AS DATETIME
    DECLARE @TotalDays AS INT
    DECLARE @DisplayDate AS VARCHAR(50)
    DECLARE @WDN AS INT
    DECLARE @WDName AS VARCHAR(20)

    SET @S_Date =CONVERT(datetime,'01/31/2019')
    SET @E_Date =CONVERT(datetime,'02/02/2019')
    SET @WDN = DATEPART(WEEKDAY,@S_Date)
    SET @WDName = DATENAME(weekday,@S_Date)
    SET @TotalDays = DATEDIFF(dd,@S_Date, DATEADD(dd,1,@E_Date))
    SET @DisplayDate =  DATENAME(weekday, @S_Date)+' ' + DATENAME(dd,@S_Date)+' '+ DATENAME(m, @S_Date)+' '+ DATENAME(yy, @S_Date)


    CREATE TABLE #Monthdaytable(
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [DisplayDate] [varchar](50) NULL,
        [Actualdate] [datetime] NULL,
        [Week_Day_Number] INT NULL,
        [Week_Day_Name] VARCHAR(20) NULL
    ) ON [PRIMARY]

    DECLARE @i AS INT
    SET @i = 1  
    WHILE(@i<=@TotalDays)
    BEGIN
        INSERT INTO #Monthdaytable
                ( DisplayDate, ActualDate ,Week_Day_Number, Week_Day_Name)
        VALUES  (@DisplayDate, @S_Date, @WDN, @WDName)
        SET @S_Date = DATEADD(dd,1,@S_Date)
        SET @WDN = DATEPART(WEEKDAY,@S_Date)
        SET @WDName = DATENAME(weekday,@S_Date)
        SET @DisplayDate =DATENAME(weekday, @S_Date)+' ' + DATENAME(dd,@S_Date)+' '+  DATENAME(m, @S_Date)+' '+ DATENAME(yy, @S_Date)
        SET @i = @i+1
    END

Just your tables:

    CREATE TABLE #HrShift (Id int, ShiftName varchar(50), DaysOfWeek varchar(500),StartTime time(7),EndTime time(7), StartDate datetime, EndDate datetime)

INSERT INTO #HrShift ( Id,  ShiftName,       DaysOfWeek, StartTime,   EndTime,     StartDate,   EndDate) VALUES (1,   'Day Shift-1',     'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday' ,    '09:00 AM' ,   '06:00 PM',    '2016-01-01' , NULL)
INSERT INTO #HrShift ( Id,  ShiftName,       DaysOfWeek, StartTime,   EndTime,     StartDate,   EndDate) VALUES (2,  'Day Shift-2' ,  'Sunday,Monday,Tuesday,Wednesday,Thursday'   ,  '10:00 AM'   , '07:00 PM' ,   '2010-01-01' , NULL)
INSERT INTO #HrShift ( Id,  ShiftName,       DaysOfWeek, StartTime,   EndTime,     StartDate,   EndDate) VALUES (3,   'Day Shift-3' ,  'Sunday,Monday,Tuesday,Wednesday,Thursday' ,    '11:00 AM'   , '08:00 PM' ,   '2010-01-01' , NULL)

    CREATE TABLE #ShiftType (Id int,  Name varchar(50))


INSERT INTO #ShiftType(Id,  Name) VALUES (1,   'Primary')
INSERT INTO #ShiftType(Id,  Name) VALUES (2,   'Roster')

CREATE TABLE #EmployeeShifts (Id int,  EmpId int,   HrShiftId int,  ShiftTypeId int,    StartDate datetime,   EndDate datetime)


INSERT INTO #EmployeeShifts(Id,  EmpId,   HrShiftId,   ShiftTypeId,     StartDate,   EndDate ) VALUES(1,   1,       1,           1,               '2018-01-01',  NULL    )
INSERT INTO #EmployeeShifts(Id,  EmpId,   HrShiftId,   ShiftTypeId,     StartDate,   EndDate ) VALUES(2,   1,       2,           2,               '2018-02-01',  '2018-02-01')
INSERT INTO #EmployeeShifts(Id,  EmpId,   HrShiftId,   ShiftTypeId,     StartDate,   EndDate ) VALUES(3,   2,       1,           1,               '2018-01-01',  NULL)
INSERT INTO #EmployeeShifts(Id,  EmpId,   HrShiftId,   ShiftTypeId,     StartDate,   EndDate ) VALUES(4,   2,       2,           2,               '2018-02-01',  '2019-02-05')
INSERT INTO #EmployeeShifts(Id,  EmpId,   HrShiftId,   ShiftTypeId,     StartDate,   EndDate ) VALUES(5,   2,       3,           2,               '2018-02-01',  '2019-02-01')


    SELECT * FROM #Monthdaytable 
    --SELECT * FROM #HrShift
    --SELECT * FROM #ShiftType
    --SELECT * FROM #EmployeeShifts

This is the query you need:

SELECT m.DisplayDate ,EmpId,ShiftName,t.Name,StartTime,EndTime
        FROM #EmployeeShifts e INNER JOIN
                #ShiftType t ON  e.ShiftTypeId = t.Id INNER JOIN
                #HrShift s ON s.Id = e.HrShiftId INNER JOIN
                #Monthdaytable m ON 1 = 1
        WHERE CONVERT(varchar,m.Actualdate,112)>=CONVERT(varchar,e.StartDate,112)
                and  CONVERT(varchar,m.Actualdate,112)<=CONVERT(varchar,ISNULL(e.EndDate, m.Actualdate),112)            
                and s.DaysOfWeek  LIKE '%'+m.Week_Day_Name+'%' 

to drop temp

    DROP TABLE #EmployeeShifts
    DROP TABLE #ShiftType
    DROP TABLE #HrShift
    DROP TABLE #Monthdaytable 

Upvotes: 1

Related Questions