2010-08-24 238 views
3

選擇我有一個表如下:在SQL Server 2005

ID | first | end 
-------------------- 
a |  1 | 3 
b |  3 | 8 
c |  8 | 10 

我想選擇如下:

ID | first | end 
--------------------- 
a-c |  1 | 10 

但我不能這樣做。請!幫我。謝謝!

回答

1

這個工作對我來說:

SELECT MIN(t.id)+'-'+MAX(t.id) AS ID, 
     MIN(t.[first]) AS first, 
     MAX(t.[end]) AS [end] 
    FROM dbo.YOUR_TABLE t 

不要使用類似 「結束」 保留字列名

+0

我明白了。但是我有一個表如下: ID第一端 b 3分配8 -C 8 10 d 15 19 E-10 12 F-19戰鬥機23 我認爲它假。 因爲我要選擇 ID第一端 一個-E 3.0 12 d-F 15 23 – 2010-08-24 03:42:33

+0

@Vuong:我認爲,雖然,你可以擴展這一理念,以滿足您的需求。如果您將計算列添加到您的選擇中以生成分組標題(考慮使用'case'語句計算列),然後對計算進行分組,您仍然可以按照此處的建議應用「MIN」和「MAX」。 – kbrimington 2010-08-24 03:52:53

+0

@Voung Mao:這是一個與你在問題中發佈的數據集不同的數據集 - 如果這是你處理的內容,你應該發佈這個問題的細節,因爲任何人都必須閱讀你的評論以瞭解其他標準。目前還不清楚你如何知道該數據集中有兩個組,或者他們開始​​和結束的位置。 – 2010-08-24 04:03:13

0

我相信你可以做到這一點使用recursive Common Table Expression如下,特別是如果你不期望的記錄很長的鏈條:

WITH Ancestors AS 
(
    SELECT 
     InitRow.[ID] AS [Ancestor], 
     InitRow.[ID], 
     InitRow.[first], 
     InitRow.[end], 
     0 AS [level], 
     '00000' + InitRow.[ID] AS [hacky_level_plus_ID] 
    FROM 
     YOUR_TABLE AS InitRow 
    WHERE 
     NOT EXISTS 
     (
      SELECT * FROM YOUR_TABLE AS PrevRow 
      WHERE PrevRow.[end] = InitRow.[first] 
     ) 
    UNION ALL 
    SELECT 
     ParentRow.Ancestor, 
     ChildRow.[ID], 
     ChildRow.[first], 
     ChildRow.[end], 
     ParentRow.level + 1 AS [level], 
     -- Avoids having to build the recursive structure more than once. 
     -- We know we will not be over 5 digits since CTEs have a recursion 
     -- limit of 32767. 
     RIGHT('00000' + CAST(ParentRow.level + 1 AS varchar(4)), 5) 
      + ChildRow.[ID] AS [hacky_level_plus_ID] 
    FROM 
     Ancestors AS ParentRow 
     INNER JOIN YOUR_TABLE AS ChildRow 
      ON ChildRow.[first] = ParentRow.[end] 
) 
SELECT 
    Ancestors.Ancestor + '-' + SUBSTRING(MAX([hacky_level_plus_ID]),6,10) AS [IDs], 
-- Without the [hacky_level_plus_ID] column, you need to do it this way: 
-- Ancestors.Ancestor + '-' + 
--  (SELECT TOP 1 Children.ID FROM Ancestors AS Children 
--  WHERE Children.[Ancestor] = Ancestors.[Ancestor] 
--  ORDER BY Children.[level] DESC) AS [IDs], 
    MIN(Ancestors.[first]) AS [first], 
    MAX(Ancestors.[end]) AS [end] 
FROM 
    Ancestors 
GROUP BY 
    Ancestors.Ancestor 
-- If needed, add OPTION (MAXRECURSION 32767) 

對各部分做一個快速的解釋:

WITH Ancestors AS (...)子句創建名稱爲Ancestors的公用表表達式(基本上是子查詢)。該表達式中的第一個SELECT建立了一個基線:在它之前沒有匹配條目的所有行。

然後,第二SELECT就是遞歸踢。因爲它引用Ancestors作爲查詢的一部分,它使用它已添加到表中的行,然後進行與新的從YOUR_TABLE加入。這將遞歸地發現越來越多的行添加到每個鏈的末尾。

最後一項是SELECT,它使用我們構建的這個遞歸表。它做了一個簡單的GROUP BY,因爲我們保存了Ancestor列中的原始ID,所以開始和結束是一個簡單的MINMAX

棘手的部分是找出鏈中最後一行的ID。有兩種方法可以做到這一點,都在查詢中說明。您可以使用遞歸表加入,在這種情況下,它將重新構建遞歸表,或者您可以嘗試跟蹤最後一個項目。 (如果構建鏈式記錄的遞歸列表的代價很高,那麼您肯定希望將您需要的次數降至最低。)

它跟蹤它的方式是跟蹤它在鏈中的位置(level列 - 注意每次我們遞歸時我們如何加1),零填充它,然後將ID粘貼到最後。然後,獲取具有最大level的項目簡單地是MAX,接着剝離level數據。

如果CTE必須遞歸太多,它會產生一個錯誤,但我相信你可以使用MAXRECURSION選項來調整。默認值爲100.如果您必須將其設置得高於此值,則可能需要考慮不使用遞歸CTE來執行此操作。

這也不能很好地處理格式錯誤的數據。如果您有兩個記錄具有相同的first或記錄first == end,那麼這將無法正常工作,您可能需要調整CTE內部的連接條件或採用其他方法。

這不是唯一的方法。我相信如果您構建自定義過程並手動完成所有步驟,將會更容易。但是這具有以單一語句操作的優點。

+0

非常感謝你。你回答簡單嗎?我只使用小型數據庫。 – 2010-08-25 03:28:44