Sql 如何根据指定持续时间下的行之间的差异“分组”事件?
我遇到的问题是,如何将几个事件组合在一起。我仅有的一个指标是两个、三个事件之间的时间。一个人正在做一些任务开始/结束-14小时内的所有事情-被视为一个工作日。好吧,现在也超过午夜了,所以约会是没有选择的。 我已经建立了一个查询,它将在第一条记录中为我指明有多少条记录属于它。这是解决问题的一种方法Sql 如何根据指定持续时间下的行之间的差异“分组”事件?,sql,sql-server-2012,Sql,Sql Server 2012,我遇到的问题是,如何将几个事件组合在一起。我仅有的一个指标是两个、三个事件之间的时间。一个人正在做一些任务开始/结束-14小时内的所有事情-被视为一个工作日。好吧,现在也超过午夜了,所以约会是没有选择的。 我已经建立了一个查询,它将在第一条记录中为我指明有多少条记录属于它。这是解决问题的一种方法 declare @MyTable table (UserID int, StartDate datetime, FinishDate datetime, GroupCount int); insert
declare @MyTable table
(UserID int, StartDate datetime, FinishDate datetime, GroupCount int);
insert into @MyTable values
('6', '2014-03-18 10:20:00.000', '2014-03-18 13:10:00.000', '2'), --(should take StartDate from this row - and Enddate from next (2) row)
('6', '2014-03-18 13:35:00.000', '2014-03-18 16:25:00.000', '1'),
('6', '2014-03-19 12:05:00.000', '2014-03-19 14:55:00.000', '1'),
('21', '2014-03-14 14:50:00.000', '2014-03-14 15:40:00.000', '1'),
('21', '2014-03-18 13:35:00.000', '2014-03-18 16:55:00.000', '1'),
('99', '2014-03-10 08:05:00.000', '2014-03-10 10:55:00.000', '2'),
('99', '2014-03-10 11:20:00.000', '2014-03-10 14:10:00.000', '1'),
('99', '2014-03-11 10:20:00.000', '2014-03-11 13:10:00.000', '2'),
('99', '2014-03-11 13:50:00.000', '2014-03-11 16:40:00.000', '1');
从@MyTable中选择*
我需要找到一种方法——以某种方式将它们组合在一起——这样我就有了最小开始日期和最大完成日期
最后,它应该是这样的:
declare @MyResult table
(UserID int, StartDate datetime, FinishDate datetime);
insert into @MyResult values
('6', '2014-03-18 10:20:00.000', '2014-03-18 16:25:00.000'),
('6', '2014-03-19 12:05:00.000', '2014-03-19 14:55:00.000'),
('21', '2014-03-14 14:50:00.000', '2014-03-14 15:40:00.000'),
('21', '2014-03-18 13:35:00.000', '2014-03-18 16:55:00.000'),
('99', '2014-03-10 08:05:00.000', '2014-03-10 14:10:00.000'),
('99', '2014-03-11 10:20:00.000', '2014-03-11 16:40:00.000');
select UserID, StartDate, Finishdate, datediff (minute, StartDate, FinishDate) as Duration,
LEAD(startdate,1,NULL) over(partition by userid order by startdate) NextDuty,
DATEDIFF(minute,FinishDate,LEAD(StartDate,1,NULL) over(partition by userid order by StartDate)) as DifMin
from @MyResult
这也取决于用户ID。群组计数-只是一个想法。。。但我不知道如何跳转2条记录-选择下一个开始-GroupCount字段等。
2将指示-当前记录和下一个记录属于一起,1仅此实际记录。
也会有3或4个记录属于一起。
所有这些都应该在MS-SQL 2012中完成。不幸的是,您的情况似乎需要遍历数据,一次遍历一行。如果条件是在至少有8小时间隔的情况下开始新的一行,那么还有其他一些可能性。但是,逻辑必须从每个客户的第一行开始,分配组,然后在确定14小时内的所有任务后,使用逻辑增加组 以下方法使用递归CTE。我能想到的唯一其他SQL替代方法是游标
with t as (
select t.*,
row_number() over (partition by UserId order by StartDate) as seqnum
from MyTable t
),
cte as (
select t.UserId, t.StartDate, t.FinishDate, seqnum,
1 as grp, t.StartDate as grp_start
from t
where seqnum = 1
union all
select t.UserId, t.StartDate, t.FinishDate, t.seqnum,
(case when t.StartDate - cte.grp_start <= 14.0/24
then cte.grp
else cte.grp + 1
end),
(case when t.StartDate - cte.grp_start <= 14.0/24
then cte.grp_start
else t.StartDate
end)
from cte join
t
on cte.UserId = t.UserId and
cte.seqnum = t.seqnum - 1
)
select userid, min(startdate), max(finishdate)
from cte
group by userid, grp
order by 1, 2;
你可以看到这项工作。我知道这个问题由来已久,但有更好的方法。鉴于您的问题比标准岛稍微复杂,我可以提供:
select t.UserID
, t.StartDate, isnull(b.FinishDate, t.FinishDate) as FinishDate
, datediff(minute, t.StartDate, isnull(b.FinishDate, t.FinishDate)) as Duration
, n.NextDuty
, datediff(minute, isnull(b.FinishDate, t.FinishDate), n.NextDuty) as DiffMin
from @MyTable t
outer apply (
select top 1 FinishDate
from @MyTable b
where b.UserID = t.UserID
and b.StartDate > t.StartDate
and datediff(hh, t.StartDate, b.StartDate) < 14
order by b.StartDate desc
) b
outer apply (
select top 1 StartDate as NextDuty
from @MyTable n
where n.UserID = t.UserID
and n.StartDate > t.StartDate
and datediff(hh, t.StartDate, n.StartDate) > 14
order by n.StartDate
) n
where not exists (
select top 1 1
from @MyTable p
where p.UserID = t.UserID
and p.StartDate < t.StartDate
and datediff(hh, p.StartDate, t.StartDate) < 14
)
在实际表中,您需要确保此索引已就位:
CREATE INDEX IX_nameThisIndex ON <@MyTable> (UserId, StartDate, FinishDate)
这应该会得到可靠的结果,我已经用其他数据进行了测试,但还没有用大数据集进行过详尽的测试。大型集合将需要索引
希望这能有所帮助。谢谢戈登的回答。现在我遇到了问题-只要我有100多条记录。。。我的声明被终止了。在语句完成之前,已耗尽最大递归100。有什么解决方法吗?好吧-使用OptionMaxRecursion 0,没有更多限制。。。它只是慢了很多-获得8000条记录的结果-700条结果-大约需要10秒但它是有效的