【问题标题】:Check if ranges are overlapping检查范围是否重叠
【发布时间】:2020-02-25 18:27:28
【问题描述】:

我有一张这样的桌子:

Id  min_val  max_val
1   5        7
2   8        12
3   4        6

如果 min_val 和 max_val 与任何其他 ID 重叠,我想得到 True/False。所以,结果如下:

Id result
1  True  
2  False 
3  True

谢谢。

【问题讨论】:

    标签: mysql sql sqlite gaps-and-islands


    【解决方案1】:

    一种方法使用exists

    select t.*,
           (exists (select 1
                    from t t2
                    where t2.id <> t.id and
                          t2.max_val > t.min_val and
                          t2.min_val < t.max_val
                   )
           ) as result;
    from t;
    

    另一种方法使用窗口函数。如果周期可以同时开始,那就有点棘手了,但想法是:

    select t.*,
           (max(max_val) over (order by min_val range between unbounded preceding and 1 preceding) > min_val) or
            min(min_val) over (order by max_val desc range between unbounded preceding and current row)
           ) as result
    from t;
    

    【讨论】:

      【解决方案2】:

      这可能有点矫枉过正,但您可以使用 JOIN,如下所示,不仅知道是否有重叠,而且知道什么是重叠的:

      SELECT t.id, tOther.id As overlappingId
      FROM t
      LEFT JOIN t AS tOther 
         ON t.id <> tOther.id            -- Not the same record
         AND t.min_val < tOther.max_val  -- Starts before "other" ends
         AND t.max_val > tOther.min_val  -- Ends after "other" starts
      ;
      

      如果您只希望每个 t 有一个结果行,则可以使用聚合来调整查询。

      SELECT t.id
          , COUNT(tOther.id) AS overlappingCount      -- Count ignores null values
          , GROUP_CONCAT(tOther.id) AS overlappingIDs -- Will be null if no overlaps
      FROM t
      LEFT JOIN t AS tOther 
         ON t.id <> tOther.id            -- Not the same record
         AND t.min_val < tOther.max_val  -- Starts before "other" ends
         AND t.max_val > tOther.min_val  -- Ends after "other" starts
      GROUP BY t.id
      ;
      

      如果您将共享边界计为重叠,只需将 &gt;&lt; 分别更改为 &gt;=&lt;=

      【讨论】:

        【解决方案3】:
        SELECT t2.id, 
        
        CASE WHEN t2.id IN
        (SELECT DISTINCT t.id
        FROM tab1 as t
        LEFT JOIN tab1 AS t1
        WHERE t.id <> t1.id AND (t.min_val < t1.max_val AND t.max_val > t.min_val)) 
        THEN "True" ELSE "False" END AS Results
        
        FROM tab1 as t2
        

        这对我有用。感谢@Uueerdo 和@Gordon Linoff

        【讨论】:

        • LEFT JOIN 没有ON 通常是不好的形式,在这种情况下基本上将LEFT JOIN 变成INNER JOIN,使用ON 而不是@ 仍然更清楚地表达987654327@。如果你想要那种格式的结果,你最好使用 Gordon 的 EXISTS 版本。
        • 谢谢@Uueerdo。我不知道这个。
        • 从技术上讲,您的解决方案可以正常工作,只是结构有点不合常规。
        猜你喜欢
        • 2016-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-10
        相关资源
        最近更新 更多