Home > Software engineering >  Get range/count of days based off a single date field
Get range/count of days based off a single date field

Time:10-02

I have requirement where i will need to get the number of days a role an employee was on.

Scenario 1

   EmployeeId    role   effectiveFrom
      1           A      1-Jan-2021
      1           B      15-Jan-2021

No further roles are available for the month of Jan for role A therefore the number of days for role A would be 14.

Scenario 2

   EmployeeId    role   effectiveFrom
      1           A      1-Jan-2021

No further roles are available for the month of Jan therefore the number of days for role A would be 31 i.e the entire month of January. For the month of February i would expect to get 28 as the role would be effective for the entire month of february as well.

Scenario 3

   EmployeeId    role   effectiveFrom
      1           A      1-Jan-2021
      1           B      15-Jan-2021
      1           A      25-Jan-2021

To get the number of days for role A the logic would be

  • 1 to 15th is 14 days.
  • 25th to 31st(31st of Jan) would be 6 days.
  • 14 6 = 20 days

The query i have come up with so far is this,

SELECT 
    DATEDIFF(MAX(effectiveFrom),
            IF(MIN(effectiveFrom) = MAX(effectiveFrom),
                MIN(effectiveFrom),
                MIN(effectiveFrom)))   1 daysWorked
FROM
    EmployeeRoles
WHERE grade = 'A'  
GROUP BY `employeeId`,effectiveFrom;

which would only give the result as 1 day for Scenario 1. Could someone guide me on the practical way of handling the scenarios. I have looked at loops, window functions but i am at a loss on the best way to proceed.

dbfiddle

CodePudding user response:

When scenario2 has 31 days from 1-jan, until the end of the month, I would suspect that from 25-jan, until the end of the month, is 7 days, and not 6, as you write in scenario3.

The number of days, using above calculation:

SELECT
   employeeID,
   grade,
   effectiveFrom,
   DATEDIFF(COALESCE(LEAD(effectiveFrom) 
                             OVER (PARTITION BY employeeID ORDER By effectiveFrom),
                     DATE_ADD(LAST_DAY(effectiveFrom),INTERVAL 1 DAY)),
            effectiveFrom) as '#Days'
FROM EmployeeRole;

This can be grouped, and summed giving:

SELECT
   employeeID,
   grade,
   SUM(`#Days`)
FROM (

SELECT
   employeeID,
   grade,
   effectiveFrom,
   DATEDIFF(COALESCE(LEAD(effectiveFrom) 
                            OVER (PARTITION BY employeeID ORDER By effectiveFrom),
                     DATE_ADD(LAST_DAY(effectiveFrom),INTERVAL 1 DAY)),
            effectiveFrom) as '#Days'
FROM EmployeeRole
) x
GROUP BY
  employeeID,
   grade;

output:

employeeID grade SUM(#Days)
1 A 14
1 B 17
2 A 31
3 A 21
3 B 10

see: DBFIDDLE

  • Related