Maximus Decimus
Maximus Decimus

Reputation: 5261

Create date ranges list

I have a start date 01/jan and end date 22/jan

My employees work 5 days consecutively and they stay at home 5 days to start to work again after these last 5 days. These 5 days are defined as policy in our company.

How can I get the working days in ranges in SQL Server? Like this

Bob starts to work from 01/jan John starts to work from 06/jan Alex starts to work from 20/jan

Period: January from 01/jan to 22/jan

Bob 01/jan - 05/jan

Bob 11/jan - 15/jan

Bob 21/jan - 22/jan

John 06/jan - 10/jan

John 16/jan - 20/jan

Alex 20/jan - 22/jan

I found this answer from this article but I don't understand the code.

How to generate a range of dates in SQL Server

Upvotes: 0

Views: 83

Answers (1)

Paul Spain
Paul Spain

Reputation: 549

Here you go! Have fun. If you need any more help just ask.

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--This is a table that holds all the people who work for you and when they started
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DECLARE @People TABLE
(
    Name        NVARCHAR(64),
    FirstDate   DATE
)

INSERT INTO @People
(
    Name,
    FirstDate
)
VALUES 
    ('Bob','01/jan/2015'),
    ('Alex','20/jan/2015'),
    ('John','6/jan/2015')

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--This is where the magic happens
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

--This is the date range you want the results for
DECLARE @StartDate  DATE = '1/JAN/2015'
DECLARE @EndDate    DATE = '22/JAN/2015'

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--Using the above dates we can make a temporary table with all the dates for this date range
--This table could be a permanent table (with all reasonable dates in) if you wanted it to be,
--but for this example we will make it from scratch each time
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DECLARE @DateTable TABLE (Date DATE)

DECLARE @Date DATE = @StartDate

--This is just a loop that inserts all the dates in the range
WHILE @Date <= @EndDate
BEGIN
    INSERT INTO @DateTable(Date) VALUES (@Date)
    SET @Date = DATEADD(D,1,@Date)
END

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--Now this is the bit you will be interested in
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

SELECT          Name,                       --Name
                MIN(Date) AS [From],        --First date
                MAX(Date) AS [To]           --Last date
FROM            @People AS P                --All people
CROSS JOIN      @DateTable AS D             --All dates
WHERE           DATEDIFF(D,FirstDate,Date) / 5 % 2 = 0      --Turn dates into groups each with 5 dates in (/5) Then pick only the even groups (%2 = 0) so one on one off
AND             FirstDate <= Date                                   --The date must be after they started
GROUP BY        Name,DATEDIFF(D,FirstDate,Date) / 5             --Group by each group so we can work out the first and last date of each group
ORDER BY        Name                                                        --Make it look nice

-----------------------------------------

If you want to change the number of days on and off, then it gets a bit more complex.

here is how you could do it

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--This is a table that holds all the people who work for you and when they started
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
DECLARE @People TABLE
(
    Name        NVARCHAR(64),
    FirstDate   DATE
)

INSERT INTO @People
(
    Name,
    FirstDate
)
VALUES 
    ('Bob','01/jan/2015'),
    ('Alex','20/jan/2015'),
    ('John','6/jan/2015')

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--This is where the magic happens
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

--This is the date range you want the results for
DECLARE @StartDate  DATE = '1/JAN/2015'
DECLARE @EndDate    DATE = '22/JAN/2015'

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--Using the above dates we can make a temporary table with all the dates for this date range
--This table could be a permanent table (with all reasonable dates in) if you wanted it to be,
--but for this example we will make it from scratch each time
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DECLARE @DateTable TABLE (Date DATE)

DECLARE @Date DATE = @StartDate

--This is just a loop that inserts all the dates in the range
WHILE @Date <= @EndDate
BEGIN
    INSERT INTO @DateTable(Date) VALUES (@Date)
    SET @Date = DATEADD(D,1,@Date)
END

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--Used for changing the number of days each perosn works vs not works
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

DECLARE  @DaysOn  INT
DECLARE  @DaysOff INT

SET @DaysOn = 5         --Days working
SET @DaysOff = 1        --Days not working

--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--Now this is the bit you will be interested in
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

SELECT   Name,
         MIN(Date) AS [From],     --First date
         MAX(Date) AS [To]        --Last date
FROM
(
   SELECT          Name,                        --Name
                   Date,                        --Date
                   ROW_NUMBER() OVER (PARTITION BY Name,DATEDIFF(D,FirstDate,Date) / (@DaysOn + @DaysOff) ORDER BY Date) AS Day,    --Day of cycle
                   DATEDIFF(D,FirstDate,Date) / (@DaysOn + @DaysOff) AS Cycle                                                       --Cycle
   FROM            @People AS P                --All people
   CROSS JOIN      @DateTable AS D             --All dates
   WHERE          FirstDate <= Date                                   --The date must be after they started
) AS Cycle
WHERE Day <= @DaysOn    --Only total up working days
GROUP BY Name,Cycle     --For each person and cycle
ORDER BY Name           --Make it looks nice

Upvotes: 1

Related Questions