以下查询允许我以小时(如果少于一天 - 转换为一天的一部分)或天(取决于不存在的长度)为单位计算两个日期之间的差异:
在缺勤表中,缺勤可以记录为 00:00 至 23:59、08:30 至 16:30(完整工作日)或一天中的几个小时,有时甚至超过工作日,示例如下13:00 至 17:15。就我而言,我只想计算 16:30 之前的部分。
我在下面的查询中遇到的问题是缺席时间超过一天,而结束日期是当天的一部分。
一个工作日为8小时(08:30至16:30)。
例如 dteStartDate = 13/04/2024 08:30 和 dteEndDAte 15/04/2024 10:45
当我想要的回报是 2.268 时,下面的查询给了我 3 个工作日的时间。
我在下面提供了一些我期望的示例数据:
dte开始日期时间 | dteEndDateTime | 工作时间损失 |
---|---|---|
27/02/2024 08:30 | 2024年2月27日16:30 | 1 |
11/03/2024 08:30 | 2024年3月11日16:30 | 1 |
2024/03/12 08:30 | 2024年3月12日16:30 | 1 |
2024年3月13日 08:30 | 2024年3月15日10:45 | 2.28125 |
2023/11/13 11:05 | 2023/11/13 17:15 | 0.6775 |
2024年1月31日14:15 | 2024年1月31日16:30 | 0.28125 |
SELECT
dteStartDateTime,
dteEndDateTime,
CASE
WHEN DATEDIFF(MINUTE, dteStartDateTime, dteEndDateTime) <= 1440 THEN
CAST(DATEDIFF(MINUTE,
CASE
WHEN CAST(dteStartDateTime AS time) < '08:30' THEN CAST(CAST(dteStartDateTime AS date) AS datetime) + CAST('08:30' AS datetime)
ELSE dteStartDateTime
END,
CASE
WHEN CAST(dteEndDateTime AS time) > '16:30' THEN CAST(CAST(dteEndDateTime AS date) AS datetime) + CAST('16:30' AS datetime)
ELSE dteEndDateTime
END
)/60.0 AS decimal(10,2))/8.0
ELSE
-- Adjusting for weekends in multi-day absences
(DATEDIFF(DAY, A.dteStartDateTime, A.dteEndDateTime) + 1)
- (DATEDIFF(WEEK, A.dteStartDateTime, A.dteEndDateTime) * 2)
END AS [Working Time Lost]
FROM TblCoverManagerAbsences A
JOIN TblCoverManagerAbsencesReasons AR ON A.intReason = AR.TblCoverManagerAbsencesReasonsId
OUTER APPLY
(
SELECT Min(txtStartDate) AS StartDate
FROM TblSchoolManagementTermDates
WHERE intSchoolYear = CASE
WHEN MONTH(getdate()) BETWEEN 9 AND 12 THEN YEAR(getdate())
ELSE YEAR(getdate()) - 1
END
) AS StartDate
WHERE
AR.txtName = 'Illness'
AND CONVERT(date, dteStartDateTime) >= CONVERT(date, StartDate.StartDate)
AND CONVERT(date, dteStartDateTime) <= DATEADD(week, DATEDIFF(week, 0, GETDATE()) - 1, 6)
我不确定如何将其与辅助日期表结合起来,以查找和检查日期范围内的每个日期。
我在 MySQL 中解决了这个问题。 同样的方式在 SQL Server 中实现..
MySQL解决方案:
with T as (
select *,
-- DAYOFWEEK(dtestartdatetime) as loginWeekDay,
-- DAYOFWEEK(dteenddatetime) as logoutWeekDay,
CAST(DATEDIFF(dteenddatetime, dtestartdatetime) AS SIGNED) AS dateDiff,
CAST(TIME_TO_SEC(cast(dtestartdatetime as TIME)) AS SIGNED) as loginTime_sec,
CAST(TIME_TO_SEC(cast(dteenddatetime as TIME)) AS SIGNED) as logoutTime_sec
from dailyLog
),
T1 as (
SELECT
CAST(TIME_TO_SEC(cast('08:30:00' as TIME)) AS SIGNED) as officialLoginTime_sec,
CAST(TIME_TO_SEC(cast('16:30:00' as TIME)) AS SIGNED) as officialLogoutTime_sec,
CAST(TIME_TO_SEC(TIMEDIFF(cast('16:30:00' as TIME), cast('08:30:00' as TIME))) AS SIGNED) as officialTotalTime
)
select T.dtestartdatetime,
T.dteenddatetime,
CASE
WHEN(T.dateDiff = 0) THEN
(T.logoutTime_sec-T.loginTime_sec)
WHEN(T.dateDiff = 1) THEN
(T.logoutTime_sec-T1.officialLogoutTime_sec) +
(T1.officialLoginTime_sec-T.loginTime_sec)
WHEN(T.dateDiff > 1) THEN
(T.logoutTime_sec-T1.officialLogoutTime_sec) +
((T1.officialLogoutTime_sec-T1.officialLoginTime_sec) * (T.dateDiff - 1)) +
(T1.officialLoginTime_sec-T.loginTime_sec)
ELSE 0
END / ((dateDiff+1) * T1.officialTotalTime) as Working_Time_Lost
from T, T1
示例输出:db<>fiddle
输出: