将累积的工作时间分配到几天

时间:2018-02-07 12:47:44

标签: sql sql-server datetime

我有引擎开始工作的日期时间以及工作时间。但有时它可以工作超过24小时。

如果在开始日期工作28小时,我将有记录

Name          started_working    Finished working     hours_worked 
obj-00123     07/02/2018 13:30   08/02/2018 17:30     28 

我需要有记录显示发动机在07年10:30和08年17:30工作。

Name          started_working    Finished working     hours_worked 
obj-00123     07/02/2018 13:30   07/02/2018 00:00     10:30 
obj-00123     07/02/2018 13:30   08/02/2018 17:30     17:30 

或类似的东西。我不知道如何才能完成这项工作。你能给我一些线索吗?如果不太容易,我不会要求编写代码。

谢谢

enter image description here

4 个答案:

答案 0 :(得分:1)

这可能会为你做到这一点

--Using CTE to show sample data
;WITH cteX( Name,started_working,Finished_working)
AS
(
    SELECT 
        'obj-00123','07/02/2018 13:30','08/02/2018 17:30' UNION ALL
    SELECT 'obj-00155','07/02/2018 15:00','07/02/2018 22:30'
)
SELECT
      X.Name
    , X.started_working
    , X.Finished_working
    , HoursWorked = CONVERT(VARCHAR(12), DATEADD(minute, DATEDIFF(minute, X.started_working, X.Finished_working), 0), 114)
FROM
(
    SELECT 
         T1.Name
        ,T1.started_working
        ,Finished_working   = DATEADD(SECOND,0,DATEADD(DAY, DATEDIFF(DAY,-1,T1.started_working),0)) -- Dummy finish time @ Midnight
    FROM
        cteX T1
    WHERE
        DATEDIFF(DAY,T1.started_working,T1.Finished_working) <> 0 --Create a dummy finish time @Midnight when start and end not on same day
    UNION ALL
    SELECT
         T2.Name
        ,started_working    = CASE WHEN DATEDIFF(DAY,T2.started_working,T2.Finished_working) <> 0
                                    THEN DATEADD(DAY, DATEDIFF(DAY, 0, T2.Finished_working), 0) --Start @ Midnight
                                    ELSE T2.started_working
                              END
        ,T2.Finished_working
    FROM
        cteX T2
) X
ORDER BY
    X.Name, X.started_working

输出

Name        started_working         Finished_working        HoursWorked
obj-00123   2018-07-02 13:30:00.000 2018-07-03 00:00:00.000 10:30:00:000
obj-00123   2018-08-02 00:00:00.000 2018-08-02 17:30:00.000 17:30:00:000
obj-00155   2018-07-02 15:00:00.000 2018-07-02 22:30:00.000 07:30:00:000

答案 1 :(得分:0)

我会接近这样的解决方案:

WITH dynamic_twelths_of_hr_table(datetime2_value) AS
(
    SELECT '2017-01-01'
    UNION ALL
    SELECT DATEADD(MINUTE, 5, datetime2_value)
    FROM dynamic_twelths_of_hr_table
    WHERE DATEADD(MINUTE, 5, datetime2_value) <= '2019-01-01'
)
,twelths_hr_table AS
(
    SELECT
        DATEADD(DAY, DATEDIFF(DAY, 0, datetime2_value), 0) AS date_value
        ,datetime2_value
    FROM dynamic_twelths_of_hr_table
)
,modified_source_table AS
(
    SELECT
        name
        ,objectid
        ,engine_start
        ,ISNULL(engine_stop, GETDATE()) AS engine_stop
        ,IIF(engine_start IS NULL OR engine_stop IS NULL, 1, 0) AS is_still_running
    FROM [YOUR_SOURCE_TABLE]
)
SELECT
    name
    ,objectid
    ,is_still_running
    ,date_value
    ,(COUNT(datetime2_value)/12.0) AS hours_run_on_this_day

FROM
    modified_source_table

LEFT JOIN
    twelths_hr_table AS tht
    ON (tht.datetime2_value BETWEEN engine_start AND engine_stop)

GROUP BY
    name, objectid, is_still_running, date_value

ORDER BY
    name, objectid, is_still_running, date_value

注意我还没有测试过这段代码,所以请原谅任何小的语法错误。

我还假设要考虑的日期范围(这些可以扩大,或根据查询运行时的动态变化),并且它有5分钟的分辨率(基于这样的事实,乍一看,我只能在engine_stop列中看到一个没有落在5分钟阈值上的值 - 所以我假设不需要5分钟以下的精度。

它的作用基本上是将每个引擎行扩展到5分钟的窗口(每小时的十二分之一),然后简单地按日分组,并计算引擎运行期间每天的窗口数。

对于当前正在运行的引擎,它将计算到目前为止运行的时间。我相信您可以根据您的具体要求调整代码。

答案 2 :(得分:0)

根据您的样本数据,工作时间可能超过几天。在这种情况下,您需要使用计数表或递归CTE。我使用了递归CTE,因为它更容易处理结果字段。此外,结果中有两列名为started_workingstarted_working2started_working来自您的预期输出,但我认为您需要started_working2

declare @T as table (
    Name varchar(100)
    , started_working datetime
    , finished_working datetime
    --, hours_worked int
)

insert into @T
values 
    ('obj-00123', '20180207 13:30', '20180208 17:30')
    , ('obj-00123', '20180208 19:00', '20180209 05:00')
    , ('obj-00123', '20180209 19:00', '20180209 22:00')
    , ('obj-00123', '20180210 19:00', '20180213 22:00')

;with rcte as (
    select
        *, started_working2 = started_working
        , next_date = cast(dateadd(dd, 1, started_working) as date), 1 step
    from 
        @T
    union all
    select
        Name, started_working, finished_working
        , cast(next_date as datetime)
        , dateadd(dd, 1, next_date), step + 1
    from
        rcte
    where
        next_date < finished_working
)

select
    Name, started_working, started_working2, finished_working
    , right(replace(str(diff / 60), ' ', 0), 2) + ':' + right(replace(str(diff % 60), ' ', 0), 2) hours_worked
from (
    select
        Name, started_working
        , case 
            when step = 1 then started_working 
            else started_working2 
        end started_working2
        , case 
            when step = max(step) over (partition by Name, started_working) 
            then finished_working else next_date 
        end finished_working
    from
        rcte
) t
cross apply (select datediff(mi, started_working2, finished_working) diff) ca

答案 3 :(得分:0)

谢谢大家。这很完美。它需要轻微的抛光和递归,需要设置为0.

但创建视图是CTE的一个问题。

创建视图mroobjectenginerowkinghoursdeclare as 将@T声明为表格(     名称nvarchar(100)     ,OBJECTID varchar(50)     ,started_working datetime     ,STOPFROM日期时间     ,开始日期时间     ,STOPDATE datetime     ,MODIFIEDDATETIME日期时间     ,START_STOP int     ,STARTDESCRIPTION nvarchar(300)     ,STOPDESCRIPTION nvarchar(300)     ,瓦数nvarchar(50)     ,用途nvarchar(300)     ,地点nvarchar(300)     ,finished_working日期时间     ,oldDiff int )

插入@T 选择     名称     ,OBJECTID     ,停下来     ,STOPFROM     ,开始日期     ,STOPDATE     ,MODIFIEDDATETIME     ,START_STOP     ,STARTDESCRIPTION     ,STOPDESCRIPTION     ,瓦数     ,目的     ,地点     ,next_stopfrom     ,DIFF     来自[MicrosoftDynamicsAX]。[dbo]。[mroobjectengineworkinghours]

;以rcte为(     选择         *,started_working2 = started_working         ,next_date = cast(dateadd(dd,1,started_working)as date),1步     从         @T     联合所有     选择         名称,OBJECTID,started_working,STOPFROM,STARTDATE,STOPDATE,MODIFIEDDATETIME,START_STOP,STARTDESCRIPTION     ,STOPDESCRIPTION,瓦数     ,目的     ,location,finished_working,oldDiff         ,cast(next_date as datetime)         ,dateadd(dd,1,next_date),步骤+ 1     从         rcte     哪里         next_date&lt; finished_working )

选择     名称,OBJECTID,started_working,STOPFROM,STARTDATE,STOPDATE,MODIFIEDDATETIME,START_STOP,STARTDESCRIPTION     ,STOPDESCRIPTION,瓦数     ,目的     ,location,oldDiff,started_working2,finished_working     ,右(替换(str(差异/ 60),&#39;&#39;,0),2)+&#39;:&#39; +右(替换(str(diff%60),&#39;&#39;,0),2)hours_worked 来自(     选择         名称,OBJECTID,started_working,STOPFROM,STARTDATE,STOPDATE,MODIFIEDDATETIME,START_STOP,STARTDESCRIPTION     ,STOPDESCRIPTION,瓦数     ,目的     ,位置,oldDiff         , 案件             当step = 1然后start_working             否则started_working2         结束started_working2         , 案件             当step = max(step)over(按名称分区,started_working)             然后finished_working else next_date         结束完成工作     从         rcte )t 交叉申请(选择datediff(mi,started_working2,finished_working)diff)ca 选项(MAXRECURSION 0);