从两个表中查找日期时间之间的时间差

时间:2016-07-29 12:21:12

标签: sql sql-server-2008

我已经尝试了一段时间解决这个问题了。 我搜索了很多,但似乎没有人有类似的问题。

这是我得到的:

Table 1 / Schedule
EmployeeID, PStart, PEnd
1, 2016-07-01 08:00:00, 2016-07-01 12:00:00
1, 2016-07-01 13:00:00, 2016-07-01 17:00:00

Table 2 / Bookings
EmployeeID, PStart, PEnd
1, 2016-07-01 08:00:00, 2016-07-01 08:40:00
1, 2016-07-01 09:00:00, 2016-07-01 10:10:00
1, 2016-07-01 10:30:00, 2016-07-01 11:00:00
1, 2016-07-01 13:00:00, 2016-07-01 15:00:00
1, 2016-07-01 15:00:00, 2016-07-01 15:30:00

我想比较这两张表并获得时间表和预订时间之间的差距。没有预订的时间。

在这个例子中

Result table / Not booked
EmployeeID, PStart, PEnd
1, 2016-07-01 08:40:00, 2016-07-01 09:00:00
1, 2016-07-01 10:10:00, 2016-07-01 10:30:00
1, 2016-07-01 11:00:00, 2016-07-01 12:00:00
1, 2016-07-01 15:30:00, 2016-07-01 17:00:00

查询的速度非常重要。员工人数超过150,所以行数很多。 我们将要使用的日期范围可能是有限的(例如,获得两周的差距),而不是显示自开始时间以来的所有差距。但只有这有助于查询速度。

提前致谢。

此致 亚当

1 个答案:

答案 0 :(得分:2)

您可以使用CTE和if(isNewInstance) { if(ctx.instance.needToUpdate){ process.nextTick(() => { ctx.instance.updateAttributes(); }); } } else { } 窗口函数的组合来完成此操作。

这个想法:

  • 按计划对您的预订进行分组,
  • 为时间表中的每个预订增加一个行号。这样您就可以将每个预订加入到以下行中。
  • 从那里,您可以选择日期,并将最后一个预订的结束日期与下一个预订的开始日期进行比较,看看日期是否正在接触。
  • 在选择查看差距时交换日期

以下是使用上述数据执行此操作的示例代码:

ROW_NUMBER()

编辑:这不适用于预订在时间表结束时。因为将选择不同的字段,所以对其进行排序的方法是使用;with allRows as ( -- give each booking an increasing row select ROW_NUMBER() OVER (PARTITION BY scheduleRow ORDER BY scheduleRow, b.PStart, b.PEnd) bookingRow, s.EmployeeId, s.scheduleRow, s.PStart as scheduleStart, s.PEnd as scheduleEnd, b.PStart as bookingStart, b.PEnd as bookingEnd from ( -- we need to add an id for our schedules (does it exist in your case?) select ROW_NUMBER() OVER (ORDER BY PStart, PEnd) scheduleRow, * FROM schedule ) s left join bookings b on -- so we can get schedules without bookings s.employeeID = b.employeeID AND s.PStart <= b.PEnd AND s.PEnd >= b.PStart ) select bookingLeft.EmployeeId, ISNULL(bookingLeft.bookingEnd, bookingLeft.scheduleStart) as PStart, ISNULL(bookingRight.bookingStart, bookingLeft.scheduleEnd) as PEnd from allRows bookingLeft left join allRows bookingRight on -- this joins the row to the one BELOW for the schedule bookingLeft.scheduleRow = bookingRight.scheduleRow and bookingLeft.bookingRow = bookingRight.bookingRow - 1 where -- this finds our gaps because the end of the last booking -- doesn't touch the start of the next booking. ISNULL(bookingLeft.bookingEnd, bookingLeft.scheduleStart) < ISNULL(bookingRight.bookingStart, bookingLeft.scheduleEnd) 。因此,可以将其添加到主脚本中,以考虑最后的预订。

UNION

如果您使用的是SQL 2012及更高版本,则可以使用LEAD(),这将消除union all -- a bit quicker than a straight UNION select bookingLeft.EmployeeId, ISNULL(bookingRight.bookingEnd, bookingLeft.scheduleStart), bookingLeft.bookingStart from allRows bookingLeft left join allRows bookingRight on -- this joins the row to the one ABOVE for the schedule bookingLeft.scheduleRow = bookingRight.scheduleRow and bookingLeft.bookingRow = bookingRight.bookingRow + 1 where ISNULL(bookingRight.bookingEnd, bookingLeft.scheduleStart) < bookingLeft.bookingStart and bookingLeft.bookingEnd >= bookingLeft.scheduleEnd -- special case when booking at the end of a schedule CTE,使查询更小。

至于性能,你可以将allRows写入临时表,打上索引,然后从中查询 - 它应该非常快。