我正在尝试找到一个可靠的查询,它返回可接受的插入范围的第一个实例。
其中InsertRange(1)是查询应返回的值。换句话说,这将是满足上述条件的第一个例子。
下面是一个示例用户表(3列),具有设置范围分布。 StartRanges总是以严格的方式排序,UserID是任意字符串,只有StartRange和EndRange的序列很重要:
StartRange EndRange UserID 312 6896 user0 7134 16268 user1 16877 22451 user2 23137 25142 user3 25955 28272 user4 28313 35172 user5 35593 38007 user6 38319 38495 user7 38565 45200 user8 46136 48007 user9
我正在尝试使用此查询:
SELECT t2.StartRange, t2.EndRange
FROM user AS t1, user AS t2
WHERE (t1.StartRange - t2.StartRange+1) > NewValue
ORDER BY t1.EndRange
LIMIT 1
根据表格,如果NewValue = 800,则返回的答案应为23137.这意味着,第一个可用的插槽位于user3和user4之间(实际插槽大小= 813):
InsertRange(1) = (StartRange(i) - EndRange(i-1)) > NewValue
InsertRange = (StartRange(6) - EndRange(5)) > NewValue
23137 = 25955 - 25142 > 800
答案 0 :(得分:0)
请记住,SQL表没有隐式行顺序。但是,通过StartRange值对表进行排序似乎是公平的。
我们可以通过编写查询来获得与前面的行配对的每一行来解决这个问题。在MySQL中,由于缺少行编号功能,很难做到这一点。
这有效(http://sqlfiddle.com/#!9/4437c0/7/0)。它可能具有令人讨厌的性能,因为它生成 O (n ^ 2)个中间行。 user0
没有排;它不能与任何前面的行配对,因为没有。
select MAX(a.StartRange) SA, MAX(a.EndRange) EA,
b.StartRange SB, b.EndRange EB , b.UserID
from user a
join user b ON a.EndRange <= b.StartRange
group by b.StartRange, b.EndRange, b.UserID
然后,您可以将其用作子查询,并应用您的条件
ORDER BY SB
LIMIT 1
这是查询(http://sqlfiddle.com/#!9/4437c0/11/0)
SELECT SB-EA Gap,
EA+1 Beginning_of_gap, SB-1 Ending_of_gap,
UserId UserID_after_gap
FROM (
select MAX(a.StartRange) SA, MAX(a.EndRange) EA,
b.StartRange SB, b.EndRange EB , b.UserID
from user a
join user b ON a.EndRange <= b.StartRange
group by b.StartRange, b.EndRange, b.UserID
) pairs
WHERE SB-EA >= 800
ORDER BY SB
LIMIT 1
请注意,您实际上可能需要最小匹配间隙而不是第一个匹配间隙。这称为最适合,而不是首先适合。为此,请改为使用ORDER BY SB-EA
。
编辑:还有另一种使用MySQL加入相邻行的方法,它没有 O (n ^ 2)性能问题。它涉及使用用户变量来模拟row_number()
函数。涉及的查询是一个毛球(这是一个技术术语)。它是在这个问题的答案的第三个备选方案中描述的。 How do I pair rows together in MYSQL?