查找范围中的间隙或重叠

时间:2015-01-15 18:35:18

标签: sql sql-server

假设我有一个包含以下格式的表:

|               dbo.ROUTES               |
 ----------------------------------------
| ID | ROUTE | LOWER_LIMIT | UPPER_LIMIT |
 ----------------------------------------
|  0 |   A   |       0     |     10      |
|  1 |   B   |      11     |    500      |
|  2 |   C   |     600     |   1000      |

如何找到路径条目未涵盖的任何数字范围?即对于上面的例子,我需要能够看到没有包含501 - 599的条目。

我们目前正在使用这种布局,虽然有4或5个其他具有各种标准的列,我们已经发现(正如您所期望的)因为表已经增长,并且已经更新了下限和上限阈值,我们开始看到空洞和重叠。

我知道这实际上归结为糟糕的设计,但在我们有资源改进它之前,我们可以做一些过时的事情,至少可以帮助我们手动整理表格。

谢谢,

4 个答案:

答案 0 :(得分:1)

由于你不能使用超前/滞后功能,我已经使用了替代方法来实现这一点。根据需要通过添加/减去1

来编辑输出列(missing_val,重叠)中的边界条件

输入:

ID  LOWER_LIMIT UPPER_LIMIT

0   0   10
1   11  500
2   600 1000
3   980 1100

输出:

ID  LOWER_LIMIT UPPER_LIMIT MISSING_VAL OVERLAPPING

0   0   10      0   0
1   11  500 500-600 0
2   600 1000    0   980-1000
3   980 1100    0   0

查询:

SELECT ID, LOWER_LIMIT, UPPER_LIMIT, CASE WHEN 
UPPER_LIMIT+1=NEXT_LOWER_VAL THEN '0' 
WHEN UPPER_LIMIT+1< NEXT_LOWER_VAL THEN
UPPER_LIMIT||'-'||NEXT_LOWER_VAL ELSE '0' END AS MISSING_VAL,
CASE WHEN 
UPPER_LIMIT+1= NEXT_LOWER_VAL THEN '0' 
 WHEN UPPER_LIMIT+1> NEXT_LOWER_VAL THEN NEXT_LOWER_VAL||'-'||UPPER_LIMIT ELSE '0' END AS       OVERLAPPING
FROM 
(
SELECT T1.*, (SELECT MIN(LOWER_LIMIT) FROM TEST_T T WHERE T.ID<> T1.ID AND T.LOWER_LIMIT>     T1.LOWER_LIMIT) AS NEXT_LOWER_VAL
FROM TEST_T T1) SUB

答案 1 :(得分:0)

这应该显示在其两侧都有间隙的行:

SELECT * FROM ROUTES 
WHERE NOT Exists(SELECT ID FROM ROUTES as sub
 WHERE sub.Lower_Limit = ROUTES.Upper_Limit + 1)
OR NOT Exists(SELECT ID FROM ROUTES as sub1
 WHERE sub1.Upper_Limit = ROUTES.Lower_Limit - 1)

答案 2 :(得分:0)

由于您使用的是SQL Server 2008,因此无法使用LEADLAG函数,因此您需要自行加入:

SELECT T2.UPPER_LIMIT + 1 AS R1
      ,T1.LOWER_LIMIT - 1 AS R2
FROM (SELECT ROW_NUMBER() OVER(ORDER BY ID) AS RID
            ,ID
            ,ROUTE  
            ,LOWER_LIMIT
            ,UPPER_LIMIT
      FROM ROUTES) AS T1
LEFT JOIN (SELECT ROW_NUMBER() OVER(ORDER BY ID) AS RID
                 ,ID
                ,ROUTE  
                ,LOWER_LIMIT
                ,UPPER_LIMIT
           FROM ROUTES) AS T2
    ON T1.RID = T2.RID + 1
WHERE T1.LOWER_LIMIT - T2.UPPER_LIMIT > 1;

在SQL Server 2012 +中:

SELECT LAG_UPPER_LIMIT + 1 AS R1
      ,LOWER_LIMIT     - 1 AS R2
FROM (SELECT ID
            ,ROUTE  
            ,LOWER_LIMIT
            ,UPPER_LIMIT
            ,LAG(UPPER_LIMIT) OVER (ORDER BY ID) AS LAG_UPPER_LIMIT
      FROM ROUTES) AS T
WHERE T.LOWER_LIMIT - T.LAG_UPPER_LIMIT > 1

这为您提供了完全缺失的范围。

答案 3 :(得分:0)

您要查找的是upper_limit值与任何内容不重叠以及下一个lower_limit值。实际上,您需要一个超过上限值而一个小于下一个下限值:

select r.upper_limit + 1 as missing_lower,
       (select min(lower_limit) - 1
        from routes r3
        where r3.lower_limit > r.upper_limit + 1
       ) as missing_higher
from routes r
where not exists (select 1
                  from routes r2
                  where r.upper_limit + 1 between r2.lower_limit and r2.upper_limit
                 );