查找工作总时间/每天多个工作/工作有时会持续到第二天

时间:2013-10-08 18:21:29

标签: sql sql-server

我对one posted here有类似的问题。

我将使用相同的DDL。但我也只改变了一个值,以说明它的不同之处。

就像这个例子一样,我也有员工在不同的开始和结束时间工作许多不同的工作,当工作时间重叠时,我不想计算任何重叠的分钟数。不同的是,在我的情况下,有些工作会在午夜到第二天进行,我不希望在第二天将工作时数作为第一天报告时间的一部分。

`USE Sandbox
GO

--CREATE TABLE Job
--(
--  JobID INT NOT NULL,
--  WorkerID INT NOT NULL,
--  JobStart DATETIME NOT NULL,
--  JobEnd DATETIME NOT NULL
--);

--INSERT INTO Job2 (JobID, WorkerID, JobStart, JobEnd)
--VALUES 
--(1, 25, '2012-11-17 16:00', '2012-11-17 17:00'),
--(2, 25, '2012-11-18 16:00', '2012-11-18 16:50'),
--(3, 25, '2012-11-19 18:00', '2012-11-20 18:30'),
--(4, 25, '2012-11-19 18:30', '2012-11-19 18:10'),
--(5, 26, '2012-11-18 16:00', '2012-11-18 17:10'),
--(6, 26, '2012-11-19 16:00', '2012-11-19 16:50');



IF OBJECT_ID('tempdb..#time') IS NOT NULL
BEGIN
drop table #time
END
DECLARE @FromDate AS DATETIME,
     @ToDate AS DATETIME,
     @Current AS DATETIME
SET @FromDate = '2012-11-17 16:00'
SET @ToDate = '2012-11-20 18:30'

create table #time  (cte_start_date datetime)
set @current = @FromDate
while (@current < @ToDate)
begin

insert into #time (cte_start_date)
values (@current)

set @current = DATEADD(n, 1, @current)

end

----query to edit
SELECT J.WorkerID 
,COUNT(DISTINCT t.cte_start_date) AS TotalTime
FROM #time AS t
INNER JOIN Job2 AS J ON t.cte_start_date >= J.JobStart AND t.cte_start_date < J.JobEnd  
GROUP BY J.WorkerID 

drop table #time`

参见JobID = 3,工作从2012-11-19 18:00开始,直到2012-11-20 18:30,第二天才结束。

结果集应为:

WorkerID 26 TotalTime 120
WorkerID 25 TotalTime 470 (and not 1580)

如何修改此查询,以便仅将6小时的jobID 3分配给11-19工作的小时数,另外6.5小时分配给11-20工作小时数?

2 个答案:

答案 0 :(得分:0)

您只需要确保临时表中的所有时间都与开始日期在同一天。我将仅发布修改后的select部分,其余部分保持不变。

在SQL Server 2008或更高版本中:

SELECT J.WorkerID 
,COUNT(DISTINCT t.cte_start_date) AS TotalTime
FROM #time AS t
INNER JOIN Job AS J ON t.cte_start_date >= J.JobStart AND t.cte_start_date < J.JobEnd
and dateadd(d, 0, t.cte_start_date as date) = cast(J.JobStart as date)
GROUP BY J.WorkerID 

在SQL Server 2005及更低版本上:

SELECT J.WorkerID 
,COUNT(DISTINCT t.cte_start_date) AS TotalTime
FROM #time AS t
INNER JOIN Job AS J ON t.cte_start_date >= J.JobStart AND t.cte_start_date < J.JobEnd
and DateAdd(d, 0, DateDiff(d, t.cte_start_date, 0)) = DateAdd(d, 0, DateDiff(d, J.JobStart, 0))
GROUP BY J.WorkerID 

修改

您可以使用以下查询获取每个日期的时间(按午夜分割) - 完整查询:

    DECLARE @FromDate AS DATETIME,
     @ToDate AS DATETIME,
     @Current AS DATETIME
SET @FromDate = '2012-11-17 16:00'
SET @ToDate = '2012-11-21 18:30'

create table #time  (cte_start_date datetime)
set @current = @FromDate
while (@current < @ToDate)
begin

insert into #time (cte_start_date)
values (@current)

set @current = DATEADD(n, 1, @current)

end

    --query to edit
SELECT J.WorkerID, CAST(t.cte_start_date as date) as WorkedDate
,COUNT(DISTINCT t.cte_start_date) AS TotalTime
FROM #time AS t
INNER JOIN Job AS J ON t.cte_start_date >= J.JobStart AND t.cte_start_date < J.JobEnd
GROUP BY J.WorkerID, CAST(t.cte_start_date as date)

答案 1 :(得分:0)

这会将跨越两天的工作分成他们自己的记录,每天一个,然后应用您已有的算法。请注意,如果作业可能超过两天,则无效:

SQL Fiddle

;with JobByDay( Day, JobId, WorkerId, StartTime, EndTime )
as
(
  select
    CAST( JobStart as Date ) Day
    , JobId
    , WorkerId
    , JobStart StartTime
    , EndTime = case
        when CAST( JobStart as Date ) < CAST( JobEnd as Date )
          then dateadd( dd, 1, CAST( JobStart as Date ) )
          else JobEnd
        end
  from
    Job

  union

  select
    CAST( JobEnd as Date ) Day
    , JobId
    , WorkerId
    , Cast( JobEnd as Date ) StartTime
    , JobEnd EndTime
  from
    Job
  where
    CAST( JobStart as Date ) < CAST( JobEnd as Date )
)

select
  * 
from
  JobByDay
order by
  WorkerId, Day