【发布时间】:2020-04-12 12:20:15
【问题描述】:
我的问题
考虑一组具有两个区间的数据。例如,考虑学生的课程表。每条记录都有一个开始和结束日期,每个班级都有一个时期开始时间和一个时期结束时间。但是从某些记录重叠的意义上说,该时间表并未“规范化”。因此,如果您搜索包含学生给定日期和期间的记录,您可能会得到多个匹配项。
这是一个人为的例子。我将日期表示为整数以简化问题:
declare @schedule table (
student char(3),
fromDate int,
toDate int,
fromPeriod int,
toPeriod int
)
insert @schedule values
('amy', 1, 7, 7, 9),
('amy', 3, 9, 5, 8),
('amy', 10, 12, 1, 3),
('ted', 1, 5, 11, 14),
('ted', 7, 11, 13, 16);
Amy 的日期和期间范围要么重叠,要么相邻。如果我查询“date 5 period 7”,我会得到两个匹配项。我需要对这些进行重新设计,以便它们代表相同的“区域”,但不再重叠。
Ted 的经期重叠,但他的日期不重叠。这意味着没有真正的重叠,因此无需重新工作。
我的研究
我已经阅读了很多关于工作重叠间隔的帖子和一些文章。即:
- Merge overlapping date intervals
- Flattening intersecting timespans
- Condense Time Periods with SQL
- SQL Server - cumulative sum on overlapping data - getting date that sum reaches a given value
- Flatten/merge overlapping time intervals
- SQL Server separate overlapping dates
我已经从 Itzik 的一篇名为“solutions-packing-date-and-time-intervals-puzzle”的博客中实现了一个,它对一个特定项目非常有效。我不认为这是一个稳定的链接,但我找到了它的副本here。
但我很难将这些资源中的知识扩展到我手头的问题。这可能是我的局限。我很难跟踪他们。我研究了 Itzik 的解决方案并且已经理解了很多,但我确实记得有一个我无法理解。或者,这些解决方案可能只适用于奇异范围。
我的尝试
我通过将范围视为文字矩形对象解决了这个问题。有用。我什至在我自己的应用程序中制作了一个性能更高的版本。因此,我会将其作为解决方案发布,以防对遇到相同问题的任何人有用。
但它是如此冗长和复杂,并且有足够的怪癖(例如缓冲线、循环形状、使用浮点值、舍入问题),我不禁认为有更好的方法。我列出的资源的概念可以扩展到双重范围吗?或者某些 SRID 是否允许切割长度为零的矩形?
预期结果:
这个问题没有唯一的答案,因为您可以聚合范围并以不同的方式解构它们。但是为了尽量减少生成的矩形的数量,实际上只有两个可以接受的答案。从视觉上看,日期在 X 轴,周期在 Y 轴,重叠的范围可以像这样开始:
+------------+
| |
| +------------+
| |||||||| | <- 2 overlapping rectangles
+----| |
| |
+------------+
我们可以这样重做:
+---+ +-----+
| | | |
| | | | +---+ <- 3 non-overlapping
| | | | | | vertically cut rectangles
+---| | | | |
| | | |
+-----+ +---+
或者这样:
+-----------+
+-----------+
+-----------------+ <- 3 non-overlapping
+-----------------+ horizontally cut rectangles
+-----------+
+-----------+
使用垂直切割,结果将如下所示:
+-------------------------------------------+
|student|fromDate|toDate|fromPeriod|toPeriod|
|-------------------------------------------|
|amy |1 |2 |7 |9 |
|amy |3 |7 |5 |9 |
|amy |8 |9 |5 |8 |
|amy |10 |12 |1 |3 |
|ted |1 |5 |11 |14 |
|ted |7 |11 |13 |16 |
+-------------------------------------------+
使用水平切割,结果如下所示:
+-------------------------------------------+
|student|fromDate|toDate|fromPeriod|toPeriod|
|-------------------------------------------|
|amy |1 |7 |9 |9 |
|amy |1 |9 |7 |8 |
|amy |3 |9 |5 |6 |
|amy |10 |12 |1 |3 |
|ted |1 |5 |11 |14 |
|ted |7 |11 |13 |16 |
+-------------------------------------------+
任何一个都可以接受。不过,为了保持它的确定性和易处理性,您需要选择一种策略并坚持下去。
【问题讨论】:
-
请向我们展示您对样本数据的预期结果。
-
这个问题没有一个答案,因为您可以聚合范围并以不同的方式重新组合它们。:所以您的结果实际上不是确定性的?这听起来像是一个不公平的要求......
-
@GMB,它很可能是确定性的。您可以编写一个算法,使用特定的输入,给出相同的预期输出。我只是说对于手头的目标可以接受不同的结果标准。
-
@GMB,重新设计了预期的结果。希望它能更好地解决您的问题。感谢您的反馈。
标签: sql-server merge range overlap rectangles