【问题标题】:SQL Server 2008 R2 looking for a way to get the night hours for an employeeSQL Server 2008 R2 正在寻找一种获取员工夜间工作时间的方法
【发布时间】:2012-07-04 18:34:20
【问题描述】:

使用 SQL Server 2008 R2,我们正在寻找一种方法来选择员工在夜间的轮班时间,在本例中为 22.00 和 6.00 +1。

我们的问题变成了如何获得轮班跨越午夜的时间,或者我们如何获得轮班从 05.30 到 22.30 开始并且在轮班开始和结束时都有重叠时的重叠时间。

这是一个例子,这些是数据库中可用的数据以及我们正在寻找的结果:

        startDateTime     |       endDateTime         |   nightHours
--------------------------+---------------------------+----------------
 2012-07-04 05:00:00.000    2012-07-04 23:00:00.000          2 
 2012-07-04 18:00:00.000    2012-07-05 05:00:00.000          7

有没有人有一个例子或一些好的指针可以使用。

【问题讨论】:

  • 示例 1 - 他们肯定工作了一整晚,+2 小时(所以 10 小时?)
  • 嗨 Damien,对不起,我已经更改了示例

标签: datetime time sql-server-2008-r2


【解决方案1】:

这可能过于复杂,但确实有效。我们使用许多 CTE 来构建有用的中间表示:

declare @Times table (
    ID int not null,
    StartTime datetime not null,
    EndTime datetime not null
)
insert into @Times (ID,StartTime,EndTime)
select 1,'2012-07-04T05:00:00.000','2012-07-04T23:00:00.000' union all
select 2,'2012-07-04T18:00:00.000','2012-07-05T05:00:00.000'

;With Start as (
    select MIN(DATEADD(day,DATEDIFF(day,0,StartTime),0)) as StartDay from @Times
), Ends as (
    select MAX(EndTime) EndTime from @Times
), Nights as (
    select DATEADD(hour,-2,StartDay) as NightStart,DATEADD(hour,6,StartDay) as NightEnd from Start
    union all
    select DATEADD(DAY,1,NightStart),DATEADD(DAY,1,NightEnd) from Nights n
    inner join Ends e on n.NightStart < e.EndTime
), Overlaps as (
    select
        t.ID,
        CASE WHEN n.NightStart > t.StartTime THEN n.NightStart ELSE t.StartTime END as StartPeriod,
        CASE WHEN n.NightEnd < t.EndTime THEN n.NightEnd ELSE t.EndTime END as EndPeriod
    from
        @Times t
            inner join
        Nights n
            on
                t.EndTime > n.NightStart and
                t.StartTime < n.NightEnd
), Totals as (
    select ID,SUM(DATEDIFF(hour,StartPeriod,EndPeriod)) as TotalHours
    from Overlaps
    group by ID
)
select
    *
from
    @Times t
        inner join
    Totals tot
        on
            t.ID = tot.ID

结果:

ID          StartTime               EndTime                 ID          TotalHours
----------- ----------------------- ----------------------- ----------- -----------
1           2012-07-04 05:00:00.000 2012-07-04 23:00:00.000 1           2
2           2012-07-04 18:00:00.000 2012-07-05 05:00:00.000 2           7

您会注意到,我必须添加一个 ID 列才能使我的关联起作用。

Start CTE 查找最早的适用午夜。 End CTE 查找我们需要查找重叠夜晚的最后时间。然后,递归的Nights CTE 每天晚上在这两个时间点之间进行计算。然后,我们将其加入到原始表(Overlaps)中,以查找每晚适用的时段。最后,在Totals 中,我们计算每个重叠时段贡献了多少小时。

这应该适用于多日活动。如果您需要计算部分小时数,您可能希望将 Totals CTE 更改为使用分钟,或应用其他一些舍入函数。

【讨论】:

  • 这绝对很棒。我添加了我们需要的字段,并毫不费力地让它在我们的数据仓库上运行。非常感谢您的帮助
【解决方案2】:

我认为,最好的方法是使用轮班开始时间和结束时间的函数。然后在函数内部有两种情况:第一种情况是在同一天开始和结束,另一种情况是在一天开始并在下一天结束。

对于在同一天开始和结束的情况做

@TotalOvernightHours=0 

@AMDifference = Datediff(hh, @shiftStart, @6amOnThatDay);
if @AMDIfference > 0 than @TotalOvernightHours = @TotalOvernightHours + @AMDifference

@PMDifference Datediff(hh, @10pmOnThatDay, @ShiftEnd)
if @PMDifference > 0 than @TotalOvernightHours = @TotalOvernightHours + @PMDifference

对于开始和结束在不同日期的情况,假设它是 2 个班次:首先从 @ShiftStart 开始,但在午夜结束。第二个从午夜开始,在@ShiftEnd 结束。并且对于每个班次都应用上面的逻辑。

如果您的轮班时间超过 24 小时,请将它们分成更小的子班次,其中午夜是一个分隔线。因此,如果您的班次从1 Jun 19:00 开始并在3 Jun 5:00 结束,那么您最终会得到三个子班次:

  • 6 月 1 日 19:00 - 6 月 1 日 24:00
  • 6 月 2 日 00:00 - 6 月 2 日 24:00
  • 6 月 3 日 00:00 - 6 月 3 日 5:00

对于每个子班次,您都会计算通宵时间。

我可能会编写一个函数来计算一个 24 小时期间的通宵时间,另一个函数将整个班次分成 24 小时块,然后将其输入第一个函数。

附言这不是sql,只是伪代码。 pps这只有在您有能力创建函数时才有效。它会为您提供干净、易于准备的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多