我有一张桌子追踪住处。有一个ID,开始日期时间,结束日期时间和其他字段。
我有另一个表,其中包含在每个逗留期间发生的事件,具有相似的开始和结束时间,并且链接在ID字段上。
我需要做的是将两者合并,然后将位置表拆分为各个事件。这里的窍门是某个地点可能开始于2017-08-02,但第一场活动可能几天都不会开始。因此,我一开始就需要记录该差距。
样本数据
CREATE TABLE #Stays (
EpID INT, StayId INT, StayStartDate DateTime, StayEndDate DateTime);
CREATE TABLE #Events (
EpID INT, EventId INT, EventStartDate DateTime, EventEndDate DateTime, EventNumber INT);
INSERT INTO #Events SELECT 1, 7897, '2016-11-24 00:00:00.000','2016-11-26 00:00:00.000', 1
INSERT INTO #Events SELECT 1, 7898, '2016-11-26 00:00:00.000','2016-11-28 00:00:00.000', 2
INSERT INTO #Stays SELECT 1, 10, '2016-11-22 08:15:00.000','2016-11-24 10:54:00.000'
INSERT INTO #Stays SELECT 1, 11, '2016-11-24 10:54:00.000','2016-11-24 11:17:00.000'
INSERT INTO #Stays SELECT 1, 12, '2016-11-24 11:17:00.000','2016-11-25 08:16:00.000'
INSERT INTO #Stays SELECT 1, 13, '2016-11-25 08:16:00.000','2016-11-28 23:15:00.000'
预期输出为
EpId StartDate EndDate EventNumber
1 2016-11-22 08:15:00.000 2016-11-23 23:59:59.000 NULL
1 2016-11-24 00:00:00.000 2016-11-25 23:59:59.000 7897
1 2016-11-26 00:00:00.000 2016-11-27 23:59:59.000 7898
1 2016-11-28 00:00:00.000 2016-11-28 23:15:00.000 NULL
这是我正在尝试的。它当前无法正常工作,我确定我正在使用的方法可能不是最佳方法。当前它没有将两个数据集融合在一起。 我的猜测是,通过外部或交叉应用可以更轻松地完成此操作,但是我对它们如何工作的了解非常有限。 有帮助吗?
;with e as (
SELECT [EpID]
,EventId
,[EventNumber]
,case when [EventStartDate] > DayStart then [EventStartDate] else DayStart end as [EventStart]
,case when [EventEndDate] < DayEnd then [EventEndDate] else DayEnd end as [EventEnd]
FROM [Events] e
inner join DimStaySegmentDayReference d on d.DayEnd >= e.[EventStartDate] and d.DayStart <= e.[EventEndDate]
),
s as (
select
[EpID]
,StayId
,case when StayStartDate > DayStart then StayStartDate else DayStart end as [StayStart]
,case when StayEndDate < DayEnd then StayEndDate else DayEnd end as [StayEnd]
from Stays s
inner join DimStaySegmentDayReference d on d.DayEnd >= StayStartDate and d.DayStart <= StayEndDate
),
u as (select 'stay' as source, [EpID], StayStart, StayEnd, '' as event from s
union all
select 'event' as source, [EpID], [EventStart], [EventEnd], eventnumber as event from e)
select Source,
[EpID],
Staystart,
stayend,
case when lag(stayend) over (partition by EpId ORDER BY STAYSTART) < StayEnd-0.0001 AND source='event' then lag(stayend) over (partition by EpId ORDER BY STAYSTART) else staystart end as staystartnew,
case when lead(staystart) over (partition by EpID ORDER BY StayStart) < stayend then lead(staystart) over (partition by EpID ORDER BY StayStart) else stayend end as stayendnew,
event
from u
where StayStart <> stayend
order by StayStart
DayReference表只是每天都有开始时间和结束时间,因此我可以将记录分为天段。
我正在使用SQL Server 2012
编辑某些上下文
我已经更新了样本数据,使其更加清晰。
停留表可跟踪位置停留。在这种情况下,我将忽略多个位置以使查找解决方案变得更加容易。
位置和事件彼此不可知,除了在同一时间范围内针对同一EpID发生之外。
例如,考虑跟踪工作时间,您从上午9点开始,到下午5点结束。对于这个工作日,您将说5个位置在组成完整的班次。 9-11桌,11-12会议,12-1午餐,1-3会议,3-5桌。
然后,您将发生一系列事件,可以称其为喝咖啡。您在9:30到10之间以及2-4之间喝咖啡。
我需要做的是将这两组数据网格在一起以创建单个时间轴。
9-930桌,930-10咖啡,10-11桌,11-12会议,12-1午餐,1-2会议,2-4咖啡,4-5桌。
希望这会有所帮助
答案 0 :(得分:0)
可能有些事情可以简化,但是很容易理解我针对每种情况验证的内容,而且,我认为您的输出示例中缺少一行,我从2018-09-14获得了最后一行16 :00至2018-09-15 12:00,我在逻辑或问题上找不到丢弃它的原因
需要额外的验证,并且不需要任何注册事件即可直接加入Stays,但这是我的方法
;WITH CTE AS (
SELECT D.*, s.StayId,
EventNumber,
LAG(D.DStart) OVER (ORDER BY EventNumber) As LagStart,
LAG(StayID) OVER (ORDER BY EventNumber) As LagStay,
LAG(Event) OVER (ORDER BY EventNumber) As LagEvent,
LEAD(D.DEnd) OVER (ORDER BY EventNumber) As LeadEnd,
LEAD(StayID) OVER (ORDER BY EventNumber) As LeadStay,
LEAD(Event) OVER (ORDER BY EventNumber) As LeadEvent
FROM #Events E
CROSS APPLY
(
SELECT TOP 1 * FROM #Stays S WHERE E.EventStartDate BETWEEN S.StayStartDate AND S.StayEndDate
UNION
SELECT TOP 1 * FROM #Stays S WHERE E.EventEndDate BETWEEN S.StayStartDate AND S.StayEndDate
) S
CROSS APPLY (
SELECT StayStartDate AS DStart, EventStartDate DEnd, Null AS Event, 1 as c WHERE StayStartDate < EventStartDate
UNION
SELECT EventStartDate, EventEndDate, EventNumber, 2 WHERE EventStartDate >= StayStartDate AND EventEndDate <= StayEndDate
UNION
SELECT StayStartDate, EventEndDate, EventNumber, 3 WHERE StayStartDate > EventStartDate AND EventEndDate < StayEndDate
UNION
SELECT EventStartDate, StayEndDate, EventNumber, 4 WHERE StayStartDate < EventStartDate AND EventEndDate > StayEndDate
UNION
SELECT EventEndDate, StayEndDate, Null, 5 WHERE EventEndDate < StayEndDate
) D
)
SELECT DISTINCT
CASE WHEN LagStay = StayId AND Event IS NULL AND LagEvent IS NULL THEN LagStart
ELSE DStart END AS StartDate,
CASE WHEN LeadStay = StayId AND Event IS NULL AND LeadEvent IS NULL THEN LeadEnd
ELSE DEnd END AS EndDate,
Event, StayID
FROM CTE
ORDER BY StartDate