寻找范围内的差距或重叠
Finding gaps or overlaps in ranges
假设我有一个 table 格式如下:
| dbo.ROUTES |
----------------------------------------
| ID | ROUTE | LOWER_LIMIT | UPPER_LIMIT |
----------------------------------------
| 0 | A | 0 | 10 |
| 1 | B | 11 | 500 |
| 2 | C | 600 | 1000 |
我如何找到路由条目未涵盖的任何号码范围?即对于上面的示例,我需要能够看到没有涵盖 501 - 599 的条目。
我们目前正在使用此布局,尽管有 4 或 5 个其他列具有不同的标准,并且我们发现(如您所料)随着 table 的增长,下限和上限阈值已更新,我们开始看到空白和重叠。
我知道这确实归结为糟糕的设计,但在我们拥有改进它的资源之前,我们可以在此期间做一些至少可以帮助我们手动整理 table 的事情。
谢谢,
这应该显示两边有空隙的行:
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)
由于您使用的是 SQL Server 2008,因此您无法使用 LEAD
和 LAG
函数,您需要自行加入:
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 服务器 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
这为您提供了准确的缺失范围。
由于您不能使用 lead/lag 函数,我使用了替代方法来实现这一点。根据需要编辑输出列中的边界条件(missing_val,重叠)adding/subtracting 1
输入:
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
您正在寻找的是不与下一个 lower_limit
值重叠的 upper_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
);
假设我有一个 table 格式如下:
| dbo.ROUTES |
----------------------------------------
| ID | ROUTE | LOWER_LIMIT | UPPER_LIMIT |
----------------------------------------
| 0 | A | 0 | 10 |
| 1 | B | 11 | 500 |
| 2 | C | 600 | 1000 |
我如何找到路由条目未涵盖的任何号码范围?即对于上面的示例,我需要能够看到没有涵盖 501 - 599 的条目。
我们目前正在使用此布局,尽管有 4 或 5 个其他列具有不同的标准,并且我们发现(如您所料)随着 table 的增长,下限和上限阈值已更新,我们开始看到空白和重叠。
我知道这确实归结为糟糕的设计,但在我们拥有改进它的资源之前,我们可以在此期间做一些至少可以帮助我们手动整理 table 的事情。
谢谢,
这应该显示两边有空隙的行:
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)
由于您使用的是 SQL Server 2008,因此您无法使用 LEAD
和 LAG
函数,您需要自行加入:
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 服务器 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
这为您提供了准确的缺失范围。
由于您不能使用 lead/lag 函数,我使用了替代方法来实现这一点。根据需要编辑输出列中的边界条件(missing_val,重叠)adding/subtracting 1
输入:
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
您正在寻找的是不与下一个 lower_limit
值重叠的 upper_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
);