【问题标题】:MS-SQL - Select Non-overlapping integer rangesMS-SQL - 选择不重叠的整数范围
【发布时间】:2017-05-06 01:36:57
【问题描述】:

我有一个包含一堆数字范围的表格,例如:

ID 开始结束
1 1200 1500
2 1450 1700
3 1800 2100
4 2500 3000
5 2900 3300

我想要做的是仅从该集合中选择不重叠的范围(例如 1,3 和 4,或 1,3 和 5)。此外,我必须能够指定一个额外的“填充”值(如中断),该值可以是可变的。因此,例如,在选择 ID=1 后,我可能希望将 400 添加到最终值(从 1500 到 1900),因此如果 ID=1 是所选范围集的一部分,则 ID=3 也不可用。

我查看了不少于 7-9 篇 SO 帖子,它们看起来都非常接近我的需要,但并非完全如此。我找到了一个可以找到重叠的:

SELECT *
FROM TEMP_Times a
JOIN TEMP_Times b on a.TimeStart <= b.TimeEnd
and a.TimeEnd >= b.TimeStart
and a.TimeID <> b.TimeID;

但是我没能把它转换成我需要的东西。如果需要递归,那很好;一次最多只能抓取 10-12 条记录。

【问题讨论】:

  • 我不清楚这种查询的预期结果是什么。正如您所指出的, (1,3,4) 和 (1,3,5) 都满足您提出的条件。 (2,3,4), (2,3,5), (1,3), (1,4), (1,5), (2,3), (2,4), (2 ,5)、(3,4) 和 (3,5)。任何单行也可以。是什么让这些解决方案中的任何一个比其他解决方案更好?
  • 需要预期的结果来获取我可以预订设备的时间列表(这些值是整数,但仅用于更快的处理 - 它们代表日期和时间)。有时需要休息来修理或翻新给定的物品。但我得到的是一个长长的从-直到值在很大程度上重叠的列表;有时几分钟,有时几个小时),所以我需要过滤掉一个完全“干净”的列表。

标签: sql-server tsql numbers range


【解决方案1】:

我认为NOT EXISTS 可以简化您的查询:

SELECT *
FROM @Test a
WHERE NOT EXISTS(
    SELECT 1
    FROM @Test b
    WHERE a.TimeStart <= b.TimeEnd AND a.TimeEnd >= b.TimeStart 
        AND a.TimeStart >= b.TimeStart
        AND a.TimeID <> b.TimeID
)

基于窗口函数的解决方案:

WITH cte AS(
    SELECT *,
        MaxEnd = MAX(TimeEnd) OVER (ORDER BY TimeStart ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
    FROM @Test
)
SELECT * 
FROM cte 
WHERE MaxEnd IS NULL OR TimeStart > MaxEnd

【讨论】:

  • 我认为这不是一个正确的答案。比如我新增一行(6,1,1000000),你可以想象你的结果。
  • 它将返回单行 (6,1,1000000)。怎么了?如果您按 TimeStart 排序,它将是第一个值
  • 在这种情况下,ID 为 1,3,4 的 3 行仍然是预期结果。
  • 选择范围时取决于排序顺序。您假设这是 TimeID,但我假设它是 TimeStart。但这并不重要:a.TimeStart &gt;= b.TimeStart可以替换为a.TimeID &gt;= b.TimeID
  • 在我的第二个解决方案中,这是明确指定的:OVER (ORDER BY TimeStart (您可以写OVER (ORDER BY TimeID 来接收@TriV 期望的结果)
猜你喜欢
  • 2022-01-25
  • 2019-01-14
  • 1970-01-01
  • 2020-04-24
  • 1970-01-01
  • 2013-06-12
  • 2018-03-03
  • 1970-01-01
  • 2013-10-21
相关资源
最近更新 更多