我的表看起来很像下面的StackOverflow URL中显示的表: Calculating total time excluding overlapped time & breaks in SQLServer
我的表还包含一个OwnerID。每个人都有一个唯一的OwnerID,我可以轻松加入属于该ID的人名。
请求的结果应该与链接的URL一样,但是每个所有者。我尝试修改他的URL的选定答案,但这给了我以下错误:
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
这是我尝试运行的查询...
;WITH addNR AS ( -- Add row numbers
SELECT StartDate, EndDate, ROW_NUMBER() OVER (ORDER BY StartDate, EndDate) AS RowID
FROM dbo.FollowUp AS T
WHERE StartDate > '2017-10-02 08:30:00.000'
), createNewTable AS ( -- Recreate table according overlap time
SELECT StartDate, EndDate, RowID
FROM addNR
WHERE RowID = 1
UNION ALL
SELECT
CASE
WHEN a.StartDate <= AN.StartDate AND AN.StartDate <= a.EndDate THEN a.StartDate
ELSE AN.StartDate END AS StartTime,
CASE WHEN a.StartDate <= AN.EndDate AND AN.EndDate <= a.EndDate THEN a.EndDate
ELSE AN.EndDate END AS EndTime,
AN.RowID
FROM addNR AS AN
INNER JOIN createNewTable AS a
ON a.RowID + 1 = AN.RowID
), getMinutes AS ( -- Get difference in minutes
SELECT DATEDIFF(MINUTE,StartDate,MAX(EndDate)) AS diffMinutes
FROM createNewTable
GROUP BY StartDate
)
SELECT SUM(diffMinutes) AS Result
FROM getMinutes
我替换了StartTime = StartDate和EndTime = EndDate,因为我的列被命名为..
答案 0 :(得分:0)
好的,这是工作代码,我不确定性能。想法:创建1分钟精度的“日历”,为每个OwnerId填充它并计算记录数
DECLARE @table TABLE (OwnerId int,StartTime DateTime2, EndTime DateTime2)
INSERT INTO @table SELECT 1,'2014-10-01 10:30:00.000', '2014-10-01 12:00:00.000'
INSERT INTO @table SELECT 1,'2014-10-01 10:40:00.000', '2014-10-01 12:00:00.000'
INSERT INTO @table SELECT 1,'2014-10-01 10:42:00.000', '2014-10-01 12:20:00.000'
INSERT INTO @table SELECT 1,'2014-10-01 10:40:00.000', '2014-10-01 13:00:00.000'
INSERT INTO @table SELECT 1,'2014-10-01 10:44:00.000', '2014-10-01 12:21:00.000'
INSERT INTO @table SELECT 1,'2014-10-13 15:50:00.000', '2014-10-13 16:00:00.000'
----------------------------------------------------------------------------
INSERT INTO @table SELECT 2,'2014-10-01 10:30:00.000', '2014-10-01 12:00:00.000'
INSERT INTO @table SELECT 2,'2014-10-01 10:40:00.000', '2014-10-01 12:00:00.000'
INSERT INTO @table SELECT 2,'2014-10-01 10:42:00.000', '2014-10-01 12:20:00.000'
declare @period int, @start datetime;;
select @period=datediff(mi, MIN(starttime),MAX(endtime)),@start =MIN(StartTime) from @table;
declare @seconds table(num int identity(0,1),garbage bit not null);
insert into @seconds(garbage) values(0);
while( select COUNT(*) from @seconds) < @period
insert into @seconds(garbage ) select garbage from @seconds;
with a(ownerId, usedminute ) as
(
select distinct t.ownerID,s.num from @seconds s join @table t on
dateadd(mi,s.num, @start) between t.StartTime and dateadd(s,-1,t.EndTime)
)
select ownerId, count(*) time_in_minutes from a group by ownerID;
答案 1 :(得分:0)
巧合@vitalygolub。
使用各种样本数据尝试我的脚本。还有时间日历表应该是永久表,所以它只是时间创建。
它不是递归的,所以它应该表现得更好。如果输出被抛出则可以避免不同。
create table #tbl (ownerid int,StartTime datetime,enddate datetime);
insert into #tbl values
(1,'2014-10-01 10:30:00.000','2014-10-01 12:00:00.000') -- 90 mins
,(1,'2014-10-01 10:40:00.000','2014-10-01 12:00:00.000') -- 0 since its overlapped with previous
,(1,'2014-10-01 10:42:00.000','2014-10-01 12:20:00.000') -- 20 mins excluding overlapped time
,(1,'2014-10-01 10:40:00.000','2014-10-01 13:00:00.000') -- 40 mins
,(1,'2014-10-01 10:44:00.000','2014-10-01 12:21:00.000') -- 0 previous ones have already covered this time range
,(1,'2014-10-13 15:50:00.000','2014-10-13 16:00:00.000') -- 10 mins
create table #Timetable(timecol time primary key )
insert into #Timetable
select dateadd(minute,(c.rn-1),'00:00')
from(
select top (24*60) row_number()over(order by number)rn from
master..spt_values order by number)c
SELECT c.ownerid
,cast(c.StartTime AS DATE)
,count(DISTINCT timecol) TimeMin
FROM #Timetable t
CROSS APPLY (
SELECT *
FROM #tbl c
WHERE timecol >= cast(c.StartTime AS TIME)
AND timecol < cast(c.enddate AS TIME)
) c
GROUP BY c.ownerid
,cast(c.StartTime AS DATE)
drop table #Timetable
drop table #tbl
答案 2 :(得分:0)
您可以在没有while
循环的情况下使用派生的计数表和基于常规集的连接来执行此操作,因此可以非常有效地执行:
-- Define test data
declare @table table (ownerid int,starttime datetime2, endtime datetime2);
insert into @table select 1,'2014-10-01 10:30:00.000', '2014-10-01 12:00:00.000';
insert into @table select 1,'2014-10-01 10:40:00.000', '2014-10-01 12:00:00.000';
insert into @table select 1,'2014-10-01 10:42:00.000', '2014-10-01 12:20:00.000';
insert into @table select 1,'2014-10-01 10:40:00.000', '2014-10-01 13:00:00.000';
insert into @table select 1,'2014-10-01 10:44:00.000', '2014-10-01 12:21:00.000';
insert into @table select 1,'2014-10-13 15:50:00.000', '2014-10-13 16:00:00.000';
----------------------------------------------------------------------------
insert into @table select 2,'2014-10-01 10:30:00.000', '2014-10-01 12:00:00.000';
insert into @table select 2,'2014-10-01 10:40:00.000', '2014-10-01 12:00:00.000';
insert into @table select 2,'2014-10-01 10:42:00.000', '2014-10-01 12:20:00.000';
-- Query
declare @MinStartTime datetime;
declare @Minutes int;
-- Define data boundaries
select @MinStartTime = min(starttime)
,@Minutes = datediff(minute,min(starttime), max(endtime))+1
from @table;
-- Initial Numbers Table - 10 rows
with t(t) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
-- Create tally table of minutes by cross joining numbers table many times to generate 1m rows
,n(n) as (select top(@Minutes) dateadd(minute,row_number() over (order by (select null))-1,@MinStartTime) from t t1, t t2, t t3, t t4, t t5, t t6)
-- Define largest possible range for each OwnerID
,o(i,s,e) as (select ownerid, min(starttime), max(endtime) from @table group by ownerid)
select o.i as OwnerID
,cast(n.n as date) as DateValue
,count(n.n) as TotalMinutes
from o
join n -- Return minutes for each OwnerID range,
on n.n between o.s and o.e
where exists(select null -- where that minute should be included.
from @table as t
where n.n >= t.starttime
and n.n < t.endtime)
group by o.i
,cast(n.n as date)
order by o.i
,DateValue
输出:
+---------+------------+--------------+
| OwnerID | DateValue | TotalMinutes |
+---------+------------+--------------+
| 1 | 2014-10-01 | 150 |
| 1 | 2014-10-13 | 10 |
| 2 | 2014-10-01 | 111 |
+---------+------------+--------------+