2015-01-15 61 views
1

假設我有以下格式的表:查找差距或重疊範圍

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

我怎麼能找到未被覆蓋的路由條目任意數量的範圍是多少?即,對於上面的示例,我需要能夠看到沒有包含501-599的條目。

我們目前正在使用此佈局,儘管有4或5個其他列有各種標準,而我們我們已經發現(如你所期望的),隨着表格的增長,並且更新了下限和上限,我們開始看到空白和重疊。

我知道這真的下降到設計不良,但直到我們擁有的資源來改善它,我們可以在臨時的東西,至少可以幫我們收拾桌子做手工。

感謝,

+0

哪個版本的SQL Server? – dario 2015-01-15 18:51:55

+0

此刻的2008 R2。 – Ahhhhbisto 2015-01-15 18:59:22

+0

@ king.code你爲什麼要問? – 2015-01-15 19:08:03

回答

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 
+0

你能解釋一下'||'的含義嗎? SSMS在'|附近返回不正確的語法'是否有一個原因,你不只是投射爲varchar並連接? – Ahhhhbisto 2015-01-16 08:36:36

+0

||是用於連接列值的oracle語法。您可以根據數據庫更改它。另外,如果您不希望值與「980-1000」類似,則可以創建兩個值爲980和1000的列(overlap_start_val,overlap_end_val)。Oracle在內部處理(將數值轉換爲字符串「980-1000」)好。我會說你應該只創建兩列而不是串聯,以便你可以很容易地查詢你的結果集。 – KSN 2015-01-16 16:09:29

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) 
+0

這隻給出了ROUTES表的內容。 – dario 2015-01-15 18:51:01

+0

如果您切換增量的方向 - (lower_limit將是'upper_limit + 1',upper_limit將是'lower_limit -1'),這將起作用。爲了防止它返回第一行和最後一行,我必須添加高低邊界。 – Ahhhhbisto 2015-01-15 19:01:08

+0

我更新它來修復邏輯 – Rono 2015-01-15 19:02:44

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 

這給你完全缺失範圍。

+0

這看起來很有希望,讓我測試並找回你。 – Ahhhhbisto 2015-01-15 19:58:06

+0

@a_horse_with_no_name是正確的。事實上,我提供了兩個不同的版本:一個用於SQL Server 2012+,一個用於以前的版本。 – dario 2015-01-15 21:05:42

0
通過加/減1

輸入編輯中的輸出列根據自己的需要的邊界條件(missing_val,重疊的)

你要找的是不與任何重疊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 
       );