如何获取两个日期范围内的天数?

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

我有 日历 table,其中包含 2021 年 12 月的所有日期(我只会举例说明 table 中的一些日期,但是据了解,它实际上包含所述月份的所有日期):

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

我有 用户 table:

ID name num_employee
01 Andrew 101
02 Mary 102

我有table帮助

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

我有一个显示员工编号、姓名、出勤天数和缺勤天数的查询:

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

通过上面的查询,我得到了这个:

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...

现在,重点是除了出勤 table,我还要考虑另一个table,叫做休假。这个table的结构如下:

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

并且考虑到这一点table,处理为休假的范围内的天数应该停止出现在“错误”列中。结果应如下所示:

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

我如何调整我的查询以获得上述内容?

考虑到我正在使用的 MariaDB 版本,有问题的查询无法适应使用 CTE。我正在开发 phpMyAdmin。

由于 MySQL 和 MariaDB 的序列不好,所以你有一个日历 table 到 运行 是很好的。

因此需要另一个检索假期日期的子查询。

我在子选择中使用了 GROUP BY,因为一个月中可能有超过 1 个假期。

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

FIND_IN_SET 需要一个字符串并且不适用于 NULL,因此您需要检查 NULL 值并替换它们

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),IFNULL(a.date,''))
           AND NOT FIND_IN_SET(EXTRACT(DAY FROM date),IFNULL(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,7,8,9,10,11

db<>fiddle here