2013-01-02 63 views
18

我有一個包含ID列和另一列包含數字的表。一個ID可以有多個數字。例如在沒有光標的情況下合併單個SQL表中的數據

ID | Number 
1 | 25 
1 | 26 
1 | 30 
1 | 24 
2 | 4 
2 | 8 
2 | 5 

現在基於這些數據,在一個新的表,我想有這樣的

ID | Low | High 
1 | 24 | 26 
1 | 30 | 30 
2 | 4 | 5 
2 | 8 | 8 

正如你所看到的,我想合併,其中的數字是連續的任何數據,如24,25,26。所以現在的低點是24點,高點是26點,然後30點仍然是一個單獨的範圍。我正在處理大量的數據,所以我寧願不使用遊標的性能(這是我以前的做法,並放慢了一些事情)...什麼是最好的方式來實現這一點?我不是SQL專業人員,所以我不確定是否有可以使這更容易的功能,或者什麼是最快的方式來完成這一點。

感謝您的幫助。

+3

您使用的RDBMS是什麼? – Taryn

+0

對不起,我在問題中添加了另一個標記。它是SQL Server 2008. –

+0

幾乎相同:[用於基於序列對結果進行分組的SQL查詢](http://stackoverflow.com/questions/5087864/sql-query-for-grouping-the-results-based-on -序列)。 –

回答

36

關鍵的觀察是一個數字序列減去另一個序列是一個常數。我們可以使用row_number生成另一個序列。這標識所有組:

select id, MIN(number) as low, MAX(number) as high 
from (select t.*, 
      (number - ROW_NUMBER() over (partition by id order by number)) as groupnum 
     from t 
    ) t 
group by id, groupnum 

其餘的只是聚合。

0

我建議使用WHILE循環結構與表變量而不是遊標。

例如,

DECLARE @TableVariable TABLE 
(
    MyID int IDENTITY (1, 1) PRIMARY KEY NOT NULL, 
    [ID] int, 
    [Number] int 
) 

DECLARE @Count int, @Max int 

INSERT INTO @TableVariable (ID, Number) 
SELECT ID, Number 
FROM YourSourceTable 

SELECT @Count = 1, @Max = MAX(MyID) 
FROM @TableVariable 

WHILE @Count <= @Max 
BEGIN 

    ...do your processing here... 


    SET @Count = @Count + 1 

END 
+0

什麼?沒有; SQL中的循環幾乎總是錯誤的。 SQL在設計時就考慮了設置邏輯,並且在編寫時利用這些優勢實現通常是最高性能的。我也有一種感覺,這種'WHILE'循環會使用一些與遊標相同的底層進程,這會讓你陷入和以前一樣糟糕的局面。除此之外,您還沒有顯示重置「@ Count」的必要條件...... –

+1

與表變量一起,有很多情況下性能增益非常值得。在這種情況下'@Count'不需要重置,只是隨着表變量中的每個記錄被處理而增加,儘管這可能根據OP的要求而改變。 –

3

解決方案與CTE和遞歸:

WITH CTE AS (
    SELECT T.ID, T.NUMBER, T.NUMBER AS GRP 
    FROM T 
    LEFT OUTER JOIN T T2 ON T.ID = T2.ID AND T.NUMBER -1 = T2.NUMBER 
    WHERE T2.ID IS NULL 
    UNION ALL 
    SELECT T.ID, T.NUMBER, GRP 
    FROM CTE 
    INNER JOIN T 
    ON T.ID = CTE.ID AND T.NUMBER = CTE.NUMBER + 1 
) 
SELECT ID, MAX(NUMBER), MIN(NUMBER) 
FROM CTE 
GROUP BY ID, GRP 

Results at fiddlesql

相關問題