2017-01-30 110 views
0

在一個表中我有兩列像下面查找頂級父ID

ID ParentID 
1 0x0 
2 1 
3 2 
9 0x0 
5 9 
6 5 
25 0x0 
30 25 

如何獲得頂級父ID
結果應該像

ID TopParentID 
3 1 
6 9 
30 25 
+4

您真的在使用2005版嗎?你應該考慮升級它。另外,您可能需要考慮升級您的問題,以將樣式數據的「花哨」「按鈕」更改爲DDL + DML。 –

+0

你想要的輸出是什麼?你想要一個列出每個「ID」的「ParentID」的表還是你指定了一個「ID」並且你只想返回那個'ParentID'? – iamdave

+0

你*真的*需要考慮升級。所有受支持的SQL Server版本都有'hierarchyid'類型,這使得ID/ParentID組合已經過時。最早支持的版本是2012. 2005年是方式,通過其生命週期結束日期 –

回答

3

另一個短CTE:

WITH cte AS(
     SELECT *, id AS topparent 
     FROM t 
     WHERE parentid IS NULL 
    UNION ALL 
     SELECT t.*, c.topparent 
     FROM t JOIN cte c ON c.id = t.parentid 
     WHERE t.id <> t.parentid 
) 
SELECT * FROM cte 

這裏測試:SQL Fiddle


編輯:這該死的SQLfiddle沒有響應一次。下面

CREATE table t (id INT, parentid INT); 
INSERT INTO T VALUES (1 , NULL); 
INSERT INTO T VALUES (2 , 1 );   
INSERT INTO T VALUES (3 , 2 );   
INSERT INTO T VALUES (9 , NULL);   
INSERT INTO T VALUES (5 , 9 );   
INSERT INTO T VALUES (6 , 5 );   
INSERT INTO T VALUES (25 , NULL);   
INSERT INTO T VALUES (30 , 25 ); 
+0

我喜歡這個 – Lamak

+1

您可以使用[rextester](http ://rextester.com/l/sql_server_online_compiler) – Lamak

3

您可以使用遞歸CTE:

WITH CTE AS 
(
    SELECT *, 1 [Level] 
    FROM dbo.YourTable 
    UNION ALL 
    SELECT A.ID, B.[Parent ID], [Level] + 1 
    FROM CTE A 
    INNER JOIN dbo.YourTable B 
     ON A.[Parent ID] = B.Id 
), CTE2 AS 
(
    SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY [Level] DESC) 
    FROM CTE 
    WHERE [Parent ID] <> 0 
) 
SELECT ID, [Parent ID] [Top Level Parent Id] 
FROM CTE2 
WHERE RN = 1 
OPTION (MAXRECURSION 0) 
; 

Here is a link with a demo

的結果是:

╔════╦═════════════════════╗ 
║ ID ║ Top Level Parent Id ║ 
╠════╬═════════════════════╣ 
║ 2 ║     1 ║ 
║ 3 ║     1 ║ 
║ 5 ║     9 ║ 
║ 6 ║     9 ║ 
║ 30 ║     25 ║ 
╚════╩═════════════════════╝ 
+0

我不認爲SQL Server 2005有'OVER'條款 –

+3

@PanagiotisKanavos嗯,它確實 – Lamak

0

測試DDL代碼如果頂級節點總是跟隨到單個葉節點的單個路徑,則所期望的結果,可以通過組合麪包屑和遞歸的CTE實現。以下示例演示了該方法:

CREATE TABLE #Items 
(
    ID    INT 
    ,[ParentID]  INT 
) 

INSERT INTO #Items 
VALUES 
(1,  0x0), 
(2,  1), 
(3,  2), 
(9,  0x0), 
(5,  9), 
(6,  5), 
(25, 0x0), 
(30, 25) 



;WITH CTE_Breadcrumbs 
AS 
(
    SELECT  ID 
       ,ParentID 
       ,CAST(ID AS NVARCHAR(1000)) AS [Path] 
       ,LEN(CAST(ID AS NVARCHAR(1000))) AS [PathLength] 
       ,ID AS [RootNodeID] 
    FROM  #Items 
    WHERE  ParentID = 0x0 
    UNION ALL 
    SELECT  Child.ID 
       ,Child.ParentID 
       ,CAST(Parent.[Path] + N'\' + CAST(Child.ID AS NVARCHAR(1000)) AS NVARCHAR(1000)) AS [Path] 
       ,LEN(CAST(Parent.[Path] + N'\' + CAST(Child.ID AS NVARCHAR(1000)) AS NVARCHAR(1000))) AS [PathLength] 
       ,CAST(
        CASE 
         WHEN CHARINDEX('\', [Path]) > 0 THEN LEFT([Path], CHARINDEX('\', [Path]) - 1) 
         ELSE Child.ParentID 
        END 
       AS INT) AS [RootNodeID] 
    FROM  #Items Child 
    INNER JOIN CTE_Breadcrumbs Parent ON Child.ParentID = Parent.ID 
) 
, 
CTE_FullPathID 
AS 
(
    SELECT  [RootNodeID] 
       ,MAX([PathLength]) AS [PathFullLength] 
    FROM  CTE_Breadcrumbs 
    GROUP BY [RootNodeID] 

) 
SELECT  CTE_Breadcrumbs.RootNodeID 
      ,CAST(
       REVERSE(
          CASE 
           WHEN CHARINDEX('\', REVERSE([Path])) > 0 THEN LEFT(REVERSE([Path]), CHARINDEX('\', REVERSE([Path])) - 1) 
           ELSE NULL 
          END 
         ) 
      AS INT) AS [LeafNodeID] 
      ,CTE_Breadcrumbs.[Path] 
FROM  CTE_Breadcrumbs 
INNER JOIN CTE_FullPathID ON CTE_Breadcrumbs.[RootNodeID] = CTE_FullPathID.[RootNodeID] AND CTE_Breadcrumbs.PathLength = CTE_FullPathID.[PathFullLength]