Home > Net >  How to get the days within a range of two dates?
How to get the days within a range of two dates?

Time:02-26

I have the calendar table with all the dates of the month of December 2021 (I will only exemplify some dates within the table, but it is understood that it actually contains all the days of said month):

ID date
01 2021-12-01
02 2021-12-02
03 2021-12-03
04 2021-12-04
05 2021-12-05

I have the users table:

ID name num_employee
01 Andrew 101
02 Mary 102

I have the table assistances

ID date num_employee
01 2021-12-03 101
02 2021-12-04 101
03 2021-12-03 102
04 2021-12-04 102
05 2021-12-05 101
06 2021-12-06 102

I have a query to display the employee number, their name, the days they attended and the days they were absent:

SELECT u.num_employee,
       u.name,
       a.date AS attendances,
        (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM calendar
           WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
           AND NOT FIND_IN_SET(EXTRACT(DAY FROM date),a.date)) as faults FROM users u
JOIN (SELECT num_employee,
      GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM attendances
      WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
      GROUP BY num_employee) a ON a.num_employee = u.num_employee

With the above query, I get this:

num_employee name attendances faults
101 Andrew 3,4,5 1,2,3,6,7,8,9,10...
102 Mary 3,4,6 1,2,5,7,8,9,10...

Now, the point is that in addition to the attendances table, I have to consider another table called vacations. The structure of this table is as follows:

id initial_date final_date num_employee
01 2021-12-07 2021-12-09 101
02 2021-12-07 2021-12-09 102

And taking this table into consideration, the days within the ranges that are handled as vacations should stop appearing in the "faults" column. The result should be the following:

num_employee name attendances faults
101 Andrew 3,4,5 1,2,3,6,10...
102 Mary 3,4,6 1,2,5,10...

How can I adapt my query to get the above?

The query in question cannot be adapted to use CTE given the version of MariaDB I am using. I am working on phpMyAdmin.

CodePudding user response:

As MySQL and MariaDB are bad with sequences, it is good that you have a calendar table to run against.

So another subquery that retrieves the dates of the vacation is needed.

I used a GROUP BY in the subselect as there could be more than 1 vacation period in a month.

SELECT u.num_employee,
       u.name,
       a.date AS attendances,
        (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM calendar
           WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
           AND NOT FIND_IN_SET(EXTRACT(DAY FROM date),a.date)
           AND NOT FIND_IN_SET(EXTRACT(DAY FROM date),vac.vac_days)) as faults 
FROM users u
LEFT JOIN  (SELECT num_employee,
      GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM attendances
      WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
      GROUP BY num_employee) a ON a.num_employee = u.num_employee
LEFT JOIN (SELECT v.`num_employee`, GROUP_CONCAT(DAY(c.`date`)) vac_days
FROM vacations v INNER JOIN calendar c ON c.`date` BETWEEN v.`initial_date` AND `final_date`
AND c. date BETWEEN '2021-12-01' AND '2021-12-31'
GROUP BY v.`num_employee`) vac ON vac.`num_employee` = u.num_employee
num_employee | name   | attendances | faults     
-----------: | :----- | :---------- | :----------
         101 | Andrew | 3,4,5       | 1,2,6,10,11
         102 | Mary   | 3,4,6       | 1,2,5,10,11

db<>fiddle here

  • Related