如何根据列值的差异在SQL中查找第一个有效行

时间:2017-03-08 23:48:48

标签: mysql

我正在尝试找到一个可靠的查询,它返回可接受的插入范围的第一个实例。

研究:

目标查询功能:

  • InsertRange(1)=(StartRange(i) - EndRange(i-1))>的NewValue

其中InsertRange(1)是查询应返回的值。换句话说,这将是满足上述条件的第一个例子。

表格结构:

  • 主键:StartRange
  • StartRange(i-1)< StartRange(ⅰ)
  • StartRange(i-1)+ EndRange(i-1)< StartRange(ⅰ)

示例数据集

下面是一个示例用户表(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

更多评论

  • 上面的查询似乎适用于紧密打包的StartRanges的特殊情况(即StartRange(i)= StartRange(i-1)+ EndRange(i-1)+ 1)。这不再适用于包装不太紧密的StartRanges

1 个答案:

答案 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

然后,您可以将其用作子查询,并应用您的条件

  1. gap&gt; = 800
  2. 第一个匹配行(最低StartRange值)ORDER BY SB
  3. 只有一个LIMIT 1
  4. 这是查询(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?