计算一天中有多个停靠点和起点的总工作时间

时间:2017-02-22 00:11:18

标签: sql sql-server

我可以使用DATEDIFF来查找一组日期之间的差异,例如

DATEDIFF(MINUTE, @startdate, @enddate)

但是如何找到多组日期之间的总时间间隔?我不知道我会有多少套(停止和开始)。

数据位于多行,包含开始和停止。

ID     TimeStamp                StartOrStop        TimeCode
----------------------------------------------------------------
1      2017-01-01 07:00:00      Start              1
2      2017-01-01 08:15:00      Stop               2
3      2017-01-01 10:00:00      Start              1
4      2017-01-01 11:00:00      Stop               2 
5      2017-01-01 10:30:00      Start              1
6      2017-01-01 12:00:00      Stop               2

3 个答案:

答案 0 :(得分:1)

此代码可以正常运行,假设您的表只存储来自一个人的数据,并且它们应该是“开始/停止/开始/停止”命令

      Query.SQL.Add ('select   "Costumer"."Name", ');
      Query.SQL.Add (         '"Costumer"."Age", ',);
      Query.SQL.Add (         '"Costumer"."Gender" ');
      Query.SQL.Add ( 'from    "Costumer" ');
      Query.SQL.Add ( 'where   "Costumer"."Name" = :aCostumerName');

答案 1 :(得分:1)

如果你的开始和停止是可靠的,这将有效。您的样品有两个开始 - 10:00和10:30开始。我假设在生产中你将有一个员工ID分组,所以我把它添加到样本数据代替标识列。

同样在生产中,CTE集将通过使用日期参数来减少。如果有隔夜轮班,您希望stops CTE在检索结束日期时使用dateadd(day, 1, @startDate)作为您的上限。

设置示例:

declare @temp table (
    EmpId int,
    TimeStamp datetime,
    StartOrStop varchar(55),
    TimeCode int
);

insert into @temp 
values
(1, '2017-01-01 07:00:00', 'Start', 1),
(1, '2017-01-01 08:15:00', 'Stop', 2),
(1, '2017-01-01 10:00:00', 'Start', 1),
(1, '2017-01-01 11:00:00', 'Stop', 2),
(2, '2017-01-01 10:30:00', 'Start', 1),
(2, '2017-01-01 12:00:00', 'Stop', 2)

<强>查询:

;with starts as (
    select  t.EmpId, 
            t.TimeStamp as StartTime,
            row_number() over (partition by t.EmpId order by t.TimeStamp asc) as rn
    from @temp t 
    where Timecode = 1 --Start time code?
),
stops as (
    select  t.EmpId, 
            t.TimeStamp as EndTime,
            row_number() over (partition by t.EmpId order by t.TimeStamp asc) as rn
    from @temp t 
    where Timecode = 2 --Stop time code?
)

select  cast(min(sub.StartTime) as date) as WorkDay, 
        sub.EmpId as Employee,
        min(sub.StartTime) as ClockIn,
        min(sub.EndTime) as ClockOut,
        sum(sub.MinutesWorked) as MinutesWorked
from 
(
    select  strt.EmpId,
            strt.StartTime, 
            stp.EndTime,
            datediff(minute, strt.StartTime, stp.EndTime) as MinutesWorked
    from starts strt
    inner join stops stp
        on strt.EmpId = stp.EmpId 
        and strt.rn = stp.rn
)sub
group by sub.EmpId

答案 2 :(得分:1)

这可以假设您的表具有增量ID和交错开始/停止记录

--Data sample as provided

declare @temp table (
    Id int,
    TimeStamp datetime,
    StartOrStop varchar(55),
    TimeCode int
);

insert into @temp 
values
(1, '2017-01-01 07:00:00', 'Start', 1),
(2, '2017-01-01 08:15:00', 'Stop', 2),
(3, '2017-01-01 10:00:00', 'Start', 1),
(4, '2017-01-01 11:00:00', 'Stop', 2),
(5, '2017-01-01 10:30:00', 'Start', 1),
(6, '2017-01-01 12:00:00', 'Stop', 2)


--let's see every pair start/stop and discard stop/start

select start.timestamp start, stop.timestamp stop, 
    datediff(mi,start.timestamp,stop.timestamp) minutes
from @temp start inner join @temp stop 
    on start.id+1= stop.id and start.timecode=1

--Sum all for required result

select sum(datediff(mi,start.timestamp,stop.timestamp) ) totalMinutes
from @temp start inner join @temp stop 
    on start.id+1= stop.id and start.timecode=1

结果

+-------------------------+-------------------------+---------+
|          start          |          stop           | minutes |
+-------------------------+-------------------------+---------+
| 2017-01-01 07:00:00.000 | 2017-01-01 08:15:00.000 |      75 |
| 2017-01-01 10:00:00.000 | 2017-01-01 11:00:00.000 |      60 |
| 2017-01-01 10:30:00.000 | 2017-01-01 12:00:00.000 |      90 |
+-------------------------+-------------------------+---------+

+--------------+
| totalMinutes |
+--------------+
|          225 |
+--------------+

也许棘手的部分是join子句。我们需要通过延迟1 @table加入ID。这是on start.id+1= stop.id开展工作的地方。

另一方面,为了排除停止/开始夫妇,我们使用start.timecode=1。如果我们没有包含此信息的列,则stop.id%2=0之类的工作正常。