按日期之间的小时和天计算缺勤

问题描述 投票:0回答:1

以下查询允许我以小时(如果少于一天 - 转换为一天的一部分)或天(取决于不存在的长度)为单位计算两个日期之间的差异:

在缺勤表中,缺勤可以记录为 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)

我不确定如何将其与辅助日期表结合起来,以查找和检查日期范围内的每个日期。

sql sql-server t-sql
1个回答
0
投票

我在 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
输出:
enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.