微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在SQL中计算员工的工作时间

如何解决如何在SQL中计算员工的工作时间

我公司的营业时间是7:30到18,而13:00到15:00是午餐时间。 重要的部分是关于午餐时间,它根本不应该算作员工的工作时间。

  • 因此,假设员工在8:30开始工作并在15:00退出,那么应该为他计算4:30小时的时间。实际上,我想从不同情况的员工的出勤时间中删除午餐时间:

enter image description here

我的字段在sql中都是Time(7)格式。

解决方法

这是SQL Server中的一种方法。它从根本上将每个人的轮班分为两个-午餐前和午餐后。轮班午餐(或过去)时,它以午餐时间为界。

我还以位(例如CTE,子查询等)的形式编写了代码,因此您可以单独运行它们以查看其作用。您可能需要针对自己的数据库结构等进行更新。

-- Data setup

CREATE TABLE #WorkLog (WorkDate date,StartTime time,EndTime time,StartLunch time,EndLunch time)

INSERT INTO #WorkLog (WorkDate,StartTime,EndTime,StartLunch,EndLunch) VALUES
('2020-09-01','07:30','18:00','13:00','15:00'),('2020-09-02','12:00','15:00',('2020-09-03',('2020-09-04','08:30','15:00')

SELECT * FROM #WorkLog

------

-- Find times worked

; WITH PreLunchTimes AS
        (SELECT WorkDate,StartTime AS StartTime,CASE WHEN EndTime < StartLunch THEN EndTime ELSE StartLunch END AS EndTime
        FROM    #WorkLog
        WHERE   StartTime < StartLunch
        ),PostLunchTimes AS
        (SELECT WorkDate,CASE WHEN StartTime > EndLunch THEN StartTime ELSE EndLunch END AS StartTime,EndTime AS EndTime
        FROM    #WorkLog
        WHERE   EndTime > EndLunch
        )
SELECT  WorkDate,SUM(Elapsed_Mins) AS Total_Work_Mins,CAST(DATEADD(minute,SUM(Elapsed_Mins),0) AS time) AS Total_work_time
FROM   (SELECT  WorkDate,DATEDIFF(minute,EndTime) AS Elapsed_Mins
        FROM    PreLunchTimes
            UNION ALL
        SELECT  WorkDate,EndTime) AS Elapsed_Mins
        FROM    PostLunchTimes
        ) AS A
GROUP BY WorkDate
ORDER BY WorkDate

这里是db<>fiddle

问题:

  • 如果您的班次超过午夜,则需要添加适当的代码来解决该问题。
  • 如果所有午餐时间都是13:00到15:00,那么您可以将它们设置为变量(例如,@LunchStart和@LunchEnd),而不是将其存储在数据中。
,

我正在发布此代码来解决您的问题

TimeSpan? ActualTime = obj.ExitTime - obj.EnterTime;
string[] LunchTime = obj.lunchTimeString.Split('-');
TimeSpan ActualLunchTime = TimeSpan.Parse(LunchTime[1].Trim()) - TimeSpan.Parse(LunchTime[0].Trim());
TimeSpan WorkingHours = TimeSpan.Parse(ActualTime.ToString().Trim()) - TimeSpan.Parse(ActualLunchTime.ToString().Trim());

在这段代码中,我所做的是:

  1. 您必须计算包括午餐时间在内的实际时间。
  2. 您的第二个问题是午餐时间,其格式为(13:00-15:00)。因此,我无法在sql中使用time(7),因此将其作为varchar并用'-'分割。
  3. 然后用它计算午餐总时间。
  4. 最后减去实际时间和实际午餐时间,即可获得工作时间。
,

A,您忘了给我们数据库表的结构。您的EnterTime和ExitTime是完整的DateTime,还是在员工开始和停止工作的那天有工作日和TimeOfDay?

除了您忘记为我们提供表结构外,我不知道您如何与数据库进行通信,使用实体框架还是使用传统的SQL,以及您说的是哪种SQL方言。有些方言可以进行DateTime计算,而另一些则不能。

MadReflection的评论很明智:如果您可以更改数据库,请考虑记住午餐前班次的开始和停止日期时间以及午餐后班次的开始/停止日期时间。这样,您就可以为将来的变化做好准备,例如每个员工甚至每天不同的午餐时间。如果您考虑使用DateTime进行输入和退出,甚至可以让员工在除夕开始工作,而在另一年停止工作。

幸运的是,您不必让数据库计算LunchTime,因为您可以在本地进行午餐时间的计算。这比让数据库管理系统计算它们并将结果从DBMS传输到本地进程要快。

本地午餐时间的计算将减去两个long,这比传输数据所需的代码快得多。

所以我们不能给您SQL。您必须编写过程来自己获取数据。

您需要一种方法来在一段时间内(或可能为所有雇员)获取每个员工的EnterTime / ExitTime。结果是这样的:

class WorkingTimes
{
     public EmployeeInformation Employee {get; set;}

     public DateTime EnterTime {get; set;}
     public DateTime ExitTime {get; set;}
}

获取每位员工或所有员工的此信息的方法:

IEnumerable<WorkingTimes> FetchWorkingTimes(DateTime beginPeriod,DateTime endPeriod)
{
    ...
}

IEnumerable<WorkingTimes> FetchWorkingTimes(int employeeId,DateTime beginPeriod,DateTime endPeriod)
{
    ...
}

要以所需的格式转换获取的数据,可以使用简单的LINQ方法:

class WorkingTimeExt
{
    // TODO: if needed: add employee information

    public System.DayOfWeek DayOfWeek => this.EnterTime.DayOfWeek;
    public DateTime EnterTime {get; set;}
    public DateTime ExitTime {get; set;}

    public DateTime StartLunch {get; set;}
    public DateTime StopLunch {get; set;}
    public string Lunch => String.Format("...",this.StartLunch,this.StopLunch);

    public TimeSpan WorkingTime => this.StartLunch - this.EnterTime
                                 + this.ExitTime - this.StopLunch;
}

WorkingTime的计算速度很快,这是一些long的加法。

TimeSpan defaultLunchStart = TimeSpan.FromHours(13.00);
TimeSpan defaultLunchEnd = TimeSpan.FromHours(15.00);

IEnumerable<WorkingTimes> fetchedWorkingTimes = ...
IEnumerable<WorkingTimesExt> result = fetchedWorkingTimes
    .Select(fetchedTimes => new WorkingTimesExt
    {
         EnterTime = fetchedWorkingTimes.EnterTime,ExitTime = fetchedWorkingTimes.ExitTime,StartLunchTime = fetchedWorkingTime.EnterTime.Date + defaultLunchStart,StopLunchTime = fetchedWorkingTime.ExitTime.Data + defaultLunchStop,});

如果您需要定期执行此操作,请考虑为其创建扩展方法:

IEnumerable<WorkingTimesExt> result = ToExtendedWorkingTimes(
     this IEnumerable<WorkingTimes> source,TimeSpan timeLunchStart,TimeSpan timeLunchStop)
{
    return source.Select(fetchedTimes => new WorkingTimesExt
    {
         EnterTime = fetchedWorkingTimes.EnterTime,StartLunchTime = fetchedWorkingTime.EnterTime.Date + timeLunchStart,StopLunchTime = fetchedWorkingTime.ExitTime.Data + timeLunchStop,});
}
,

将工作时间转换为HH:MM格式的另一个工作选项:

CREATE TABLE t1 (dow VARCHAR(10),workstart TIME,workend TIME);
INSERT INTO t1 VALUES
('Monday','7:30','18:00'),('Tuesday',('Wednesday',('Thursday','8:30','15:00');

WITH 
lunch(lunchstart,lunchend) AS (
SELECT CAST('13:00' AS TIME),CAST('15:00' AS TIME)
),attendances AS (
SELECT *,CASE WHEN workstart <= lunchstart THEN
     CASE WHEN workend <= lunchstart THEN
          DATEDIFF(minute,workstart,workend)
     ELSE
          DATEDIFF(minute,lunchstart)
     END
ELSE 0 END --AS morning_shift
+
CASE WHEN workend >= lunchend THEN
     CASE WHEN workstart >= lunchend THEN
          DATEDIFF(minute,lunchend,workend)
     END
ELSE 0 END --AS afternoon_shift 
AS total_mins 
FROM t1,lunch
)
SELECT *,FORMAT(total_mins / 60 * 100 + total_mins % 60,'#:0#') AS hhmm 
FROM attendances;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。