如何计算每小时工作时数

时间:2016-09-19 15:06:14

标签: sql-server

我正在尝试在我们的生产线上创建可视化。我们有两条线路,有几百人,每个都有不同的人员轮班策略。通过循环记录,我已经能够在Access中生成我想要的结果。 我想将其升级到SQL Server并提高速度。

有人可以指出我正确的方向吗?

enter image description here

以下是适用于Access的VBA代码。

Public Function MakeLaborData()

Dim db As dao.Database
Dim rs As dao.Recordset
Dim hr As Date
Dim LaborOn As Date
Dim LaborOff As Date
Dim Hours As Double

Set db = CurrentDb
Set rs1 = db.OpenRecordset("t_Labor") 'myTable is a MS-Access table created previously
Set rs2 = db.OpenRecordset("t_Labor_by_Hour")

Do While Not rs1.EOF
    LaborOn = rs1.Fields("LABOR_ON").Value
    If IsNull(rs1.Fields("LABOR_OFF").Value) Then
      LaborOff = Now()
    Else
      LaborOff = rs1.Fields("LABOR_OFF").Value
    End If

hr = DateSerial(DatePart("yyyy", LaborOn), DatePart("m", LaborOn), DatePart("d", LaborOn)) + (DatePart("h", LaborOn) / 24)

Do Until hr > LaborOff
  If LaborOn > hr And LaborOff < hr + 1 / 24 Then
    Hours = (LaborOff - LaborOn) * 24

    ElseIf LaborOn > hr And LaborOff > hr + 1 / 24 Then
      Hours = ((hr + 1 / 24) - LaborOn) * 24

    ElseIf LaborOn < hr And LaborOff > hr + 1 / 24 Then
      Hours = 1

    ElseIf LaborOn < hr And LaborOff < hr + 1 / 24 Then
      Hours = (LaborOff - hr) * 24

    Else
      Hours = 0

  End If

  With rs2
    .AddNew
    !Line_Number = rs1!UNIT
    !SOI = rs1!JOB
    !Employee = rs1!Employee
    !Hour_of_Day = hr
    !Labor_Hours = Hours
    .Update
  End With

  hr = hr + 1 / 24
Loop



rs1.MoveNext

Loop

rs1.Close
rs2.Close

End Function

2 个答案:

答案 0 :(得分:2)

我建议一个表格,其中包含每个班次(工作期间)的开始和停止时间,因此如果Bob工作1.75小时,那么Bob将在早上6:30开始并在8点停止:上午15点。您需要在三个工作小时内显示此信息是一个演示问题,而不是数据问题。您可以在上午12点到中午12点之间每小时都有一个“小时”表。如果您使用此新表加入Hour表,则会获得3个结果。

答案 1 :(得分:2)

您可以使用递归CTE(递归公用表表达式)生成小时的集合。

接下来,您必须加入员工数据,其中劳动时间和劳动力关闭之间的小时数

保留仅添加CASE WHEN子句以计算小时数

看看这个解决方案:

declare @dataTable table(UNIT int, JOB varchar(5), EMPLOYEE nvarchar(50), LABOR_ON datetime2(0), LABOR_OFF datetime2(0))
INSERT INTO @dataTable
(UNIT, JOB, EMPLOYEE, LABOR_ON, LABOR_OFF)
VALUES
(398,'W9714',N'Ley',DATETIMEFROMPARTS(2015,12,16,11,46,39,0), DATETIMEFROMPARTS(2015,12,16,12,20,07,0)),
(398,'WSP06',N'Cervantes',DATETIMEFROMPARTS(2016,01,22,11,30,28,0), DATETIMEFROMPARTS(2016,1,22,12,25,56,0)),
(398,'DN3RT',N'Miller',DATETIMEFROMPARTS(2015,11,2,13,40,46,0), DATETIMEFROMPARTS(2015,11,2,15,01,12,0)),
(398,'N04TA',N'Kitzmiller',DATETIMEFROMPARTS(2015,10,20,16,22,02,0), DATETIMEFROMPARTS(2015,10,20,19,06,21,0)),
(398,'N2C54',N'Blackwell',DATETIMEFROMPARTS(2015,12,14,5,38,30,0), DATETIMEFROMPARTS(2015,12,14,10,34,46,0)),
(398,'NP02M',N'Perryman',DATETIMEFROMPARTS(2015,10,31,5,20,49,0), DATETIMEFROMPARTS(2015,10,31,12,53,43,0));

WITH hourCTE as (SELECT 0 as [HourNo]
UNION ALL
SELECT [HourNo] + 1 FROM hourCTE WHERE [HourNo] < 23
),
DataWithHours as (
SELECT UNIT
,JOB
,EMPLOYEE
,dateadd(hour,HourNo,cast(cast(LABOR_ON as date) as datetime)) as Hour_of_day
,LABOR_ON
,LABOR_OFF
,hourNo
FROM hourCTE
join @dataTable on [HourNo] between DATEPART(HOUR,LABOR_ON) and DATEPART(HOUR,LABOR_OFF))

SELECT UNIT
,JOB
,EMPLOYEE
,Hour_of_day
,
cast(CASE WHEN DATEPART(HOUR,LABOR_ON) = HourNo
THEN
DATEDIFF(SECOND,LABOR_ON,DATEADD(HOUR, 1, Hour_of_day))/cast(3600.0 as decimal)
WHEN DATEPART(HOUR,LABOR_OFF) = HourNo
THEN
DATEDIFF(SECOND,Hour_of_day,LABOR_OFF)/cast(3600.0 as decimal)
ELSE
1.000
END as decimal(6,5)) as Labor_Hours
FROM DataWithHours
order by unit,  EMPLOYEE, HourNo