如何只计算两个日期之间的工作日?
How to count only the working days between two dates?
我有以下 table 称为 假期,其中显示员工编号及其假期的开始和结束日期:
id_employe
start
end
1001
2020-12-24
2021-01-04
我正在寻找的是可视化每个员工的休假天数,但按员工编号、月、年和天数将它们分开;不考虑非工作日(周六、周日和节假日)。
我有以下查询,它设法从发布中省略星期六和星期日:
SELECT id_employee,
EXTRACT(YEAR FROM t.Date) AS year,
EXTRACT(MONTH FROM t.Date) AS month,
SUM(WEEKDAY(`Date`) < 5) AS days
FROM (SELECT v.id_employee,
DATE_ADD(v.start, interval s.seq - 1 DAY) AS Date
FROM vacations v CROSS JOIN seq_1_to_100 s
WHERE DATE_ADD(v.start, interval s.seq - 1 DAY) <= v.end
ORDER BY v.id_employee, v.start, s.seq ) t
GROUP BY id_employee, EXTRACT(YEAR_MONTH FROM t.Date);
我的问题是,除了周末,我怎么能不放假呢?我想我应该建立另一个 table 来存储这些假期的日期,但是我的 * 查询 * 如何适应执行比较?
如果我们考虑员工 1001 从 2020-12-24 休假到 2021-01 -04 并且我们把圣诞节和新年作为假期,我们应该得到以下结果:
id_employee
month
year
days
1001
12
2020
5
1001
1
2021
1
在你创建了一个存储假期日期的 table 之后,你可能可以这样做:
SELECT id_employee,
EXTRACT(YEAR FROM t.Date) AS year,
EXTRACT(MONTH FROM t.Date) AS month,
SUM(CASE WHEN h.holiday_date IS NULL THEN WEEKDAY(`Date`) < 5 END) AS days
FROM (SELECT v.id_employee,
DATE_ADD(v.start, interval s.seq - 1 DAY) AS Date
FROM vacations v CROSS JOIN seq_1_to_100 s
WHERE DATE_ADD(v.start, interval s.seq - 1 DAY) <= v.end
ORDER BY v.id_employee, v.start, s.seq ) t
LEFT JOIN holidays h ON t.date=h.holiday_date
GROUP BY id_employee, EXTRACT(YEAR_MONTH FROM t.Date);
假设 holidays
table 结构是这样的:
CREATE TABLE holidays (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
holiday_date DATE,
holiday_description VARCHAR(255));
然后 LEFT JOIN
将其添加到您当前的查询并通过添加 CASE
表达式来检查 SUM()
稍微更改。如果left join中的ON t.date=h.holiday_date
匹配,则结果为字段h.holiday_date
,否则为NULL
,因此只考虑CASE h.holiday_date WHEN IS NULL ..
。[=23] =]
添加此解决方案与 MariaDB 和支持 common table expression 的 MySQL 版本兼容:
WITH RECURSIVE cte AS
(SELECT id_employee, start, start lvdt, end FROM vacations
UNION ALL
SELECT id_employee, start, lvdt+INTERVAL 1 DAY, end FROM cte
WHERE lvdt+INTERVAL 1 DAY <=end)
SELECT id_employee,
YEAR(v.lvdt) AS year,
MONTH(v.lvdt) AS month,
SUM(CASE WHEN h.holiday_date IS NULL THEN WEEKDAY(v.lvdt) < 5 END) AS days
FROM cte v
LEFT JOIN holidays h
ON v.lvdt=h.holiday_date
GROUP BY id_employee,
YEAR(v.lvdt),
MONTH(v.lvdt);
我有以下 table 称为 假期,其中显示员工编号及其假期的开始和结束日期:
id_employe | start | end |
---|---|---|
1001 | 2020-12-24 | 2021-01-04 |
我正在寻找的是可视化每个员工的休假天数,但按员工编号、月、年和天数将它们分开;不考虑非工作日(周六、周日和节假日)。
我有以下查询,它设法从发布中省略星期六和星期日:
SELECT id_employee,
EXTRACT(YEAR FROM t.Date) AS year,
EXTRACT(MONTH FROM t.Date) AS month,
SUM(WEEKDAY(`Date`) < 5) AS days
FROM (SELECT v.id_employee,
DATE_ADD(v.start, interval s.seq - 1 DAY) AS Date
FROM vacations v CROSS JOIN seq_1_to_100 s
WHERE DATE_ADD(v.start, interval s.seq - 1 DAY) <= v.end
ORDER BY v.id_employee, v.start, s.seq ) t
GROUP BY id_employee, EXTRACT(YEAR_MONTH FROM t.Date);
我的问题是,除了周末,我怎么能不放假呢?我想我应该建立另一个 table 来存储这些假期的日期,但是我的 * 查询 * 如何适应执行比较?
如果我们考虑员工 1001 从 2020-12-24 休假到 2021-01 -04 并且我们把圣诞节和新年作为假期,我们应该得到以下结果:
id_employee | month | year | days |
---|---|---|---|
1001 | 12 | 2020 | 5 |
1001 | 1 | 2021 | 1 |
在你创建了一个存储假期日期的 table 之后,你可能可以这样做:
SELECT id_employee,
EXTRACT(YEAR FROM t.Date) AS year,
EXTRACT(MONTH FROM t.Date) AS month,
SUM(CASE WHEN h.holiday_date IS NULL THEN WEEKDAY(`Date`) < 5 END) AS days
FROM (SELECT v.id_employee,
DATE_ADD(v.start, interval s.seq - 1 DAY) AS Date
FROM vacations v CROSS JOIN seq_1_to_100 s
WHERE DATE_ADD(v.start, interval s.seq - 1 DAY) <= v.end
ORDER BY v.id_employee, v.start, s.seq ) t
LEFT JOIN holidays h ON t.date=h.holiday_date
GROUP BY id_employee, EXTRACT(YEAR_MONTH FROM t.Date);
假设 holidays
table 结构是这样的:
CREATE TABLE holidays (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
holiday_date DATE,
holiday_description VARCHAR(255));
然后 LEFT JOIN
将其添加到您当前的查询并通过添加 CASE
表达式来检查 SUM()
稍微更改。如果left join中的ON t.date=h.holiday_date
匹配,则结果为字段h.holiday_date
,否则为NULL
,因此只考虑CASE h.holiday_date WHEN IS NULL ..
。[=23] =]
添加此解决方案与 MariaDB 和支持 common table expression 的 MySQL 版本兼容:
WITH RECURSIVE cte AS
(SELECT id_employee, start, start lvdt, end FROM vacations
UNION ALL
SELECT id_employee, start, lvdt+INTERVAL 1 DAY, end FROM cte
WHERE lvdt+INTERVAL 1 DAY <=end)
SELECT id_employee,
YEAR(v.lvdt) AS year,
MONTH(v.lvdt) AS month,
SUM(CASE WHEN h.holiday_date IS NULL THEN WEEKDAY(v.lvdt) < 5 END) AS days
FROM cte v
LEFT JOIN holidays h
ON v.lvdt=h.holiday_date
GROUP BY id_employee,
YEAR(v.lvdt),
MONTH(v.lvdt);