1

我有一个与此处发布的问题类似的问题。

我将使用相同的 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 的工作时间?

4

2 回答 2

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)
于 2013-10-08T19:34:02.377 回答
0

这会将跨越两天的作业分成自己的记录,每天一份,然后应用您已有的算法。请注意,如果作业可能跨越两天以上,这将不起作用:

SQL小提琴

;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
于 2013-10-08T19:48:55.957 回答