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

发布于 2025-01-10 10:14:42 字数 2988 浏览 0 评论 0原文

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

ID日期
012021-12-01
022021-12-02
032021-12-03
042021-12-04
052021-12-05

我有users表:

IDnamenum_employee
01Andrew101
02Mary102

我有表assistances

IDdatenum_employee
012021-12-03101
022021-12-04101
032021-12-03102
042021-12-04102
052021-12-05101
062021-12-06102

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

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_employeenameattendsfailure
101安德鲁3,4,51,2,3,6,7,8,9,10...
102玛丽3,4,61,2,5,7,8,9,10...

现在,重点是,除了出勤表之外,我还必须考虑另一个名为假期的表。该表的结构如下:

idinitial_dateFinal_datenum_employee
012021-12-072021-12-09101
022021-12-072021-12-09102

考虑到该表,范围内的天数处理为假期应该停止出现在“故障”列中。结果应如下:

num_employeenameattendsfailure
101Andrew3,4,51,2,3,6,10...
102Mary3,4,61,2,5,10...

我怎样才能调整我的查询以获得上述内容?

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

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):

IDdate
012021-12-01
022021-12-02
032021-12-03
042021-12-04
052021-12-05

I have the users table:

IDnamenum_employee
01Andrew101
02Mary102

I have the table assistances

IDdatenum_employee
012021-12-03101
022021-12-04101
032021-12-03102
042021-12-04102
052021-12-05101
062021-12-06102

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_employeenameattendancesfaults
101Andrew3,4,51,2,3,6,7,8,9,10...
102Mary3,4,61,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:

idinitial_datefinal_datenum_employee
012021-12-072021-12-09101
022021-12-072021-12-09102

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_employeenameattendancesfaults
101Andrew3,4,51,2,3,6,10...
102Mary3,4,61,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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

难忘№最初的完美 2025-01-17 10:14:42

由于 MySQL 和 MariaDB 不擅长处理序列,因此最好有一个日历表来运行。

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

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

选择 u.num_employee,
       你的名字,
       a.AS 出席日期,
        (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS 日历中的日期
           “2021-12-01”和“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)) 作为错误 
来自用户 u
左连接(选择 num_employee,
      GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS 出勤日期
      “2021-12-01”和“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 假期 v INNER JOIN 日历 c ON c.`date` BETWEEN v.`initial_date` AND `final_date`
和c。 “2021-12-01”和“2021-12-31”之间的日期
GROUP BY v.`num_employee`) vac ON vac.`num_employee` = u.num_employee

<前>num_employee |名称 |出席人数 |故障
------------: | :----- | :---------- | :----------
101 | 101安德鲁 | 3,4,5 | 1,2,6,10,11
102 | 102玛丽| 3,4,6 | 1,2,5,10,11

db<>fiddle 此处

FIND_IN_SET 需要一个字符串,不能与 NULL 一起使用,所以你需要检查 NULL 值并替换它们

SELECT u.num_employee,
       你的名字,
       a.AS 出席日期,
        (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS 日历中的日期
           “2021-12-01”和“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,''))
           ) 作为故障 
来自用户 u
左连接(选择 num_employee,
      GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS 出勤日期
      “2021-12-01”和“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 假期 v INNER JOIN 日历 c ON c.`date` BETWEEN v.`initial_date` AND `final_date`
和c。 “2021-12-01”和“2021-12-31”之间的日期
GROUP BY v.`num_employee`) vac ON vac.`num_employee` = u.num_employee

<前>num_employee |名称 |出席人数 |故障
------------: | :----- | :---------- | :----------------
101 | 101安德鲁 | 3,4,5 | 1,2,6,10,11
102 | 102玛丽| 3,4,6 | 1,2,5,7,8,9,10,11

db<>fiddle 此处

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

FIND_IN_SET needs a string and doesn't work with NULL, so you need to check for NULL Values and replace them

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文