如何获取两个日期范围内的天数?
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
我有 日历 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