2016-04-22 66 views
5

我遇到了困難的時間。我已經看到了一些關於如何從給定父母的自引用表中獲取所有子記錄以及如何獲取子記錄父母的例子。選擇所有層次結構級別及以下SQL Server

我想要做的是返回一個記錄和給定ID的所有子記錄。

將此放入上下文中 - 我有一個公司層次結構。其中:

#Role  Level# 
-------------------- 
Corporate   0 
Region   1 
District   2 
Rep    3 

我需要的是:(1)計算出的記錄是什麼樣的水平;(2)檢索記錄和所有的孩子記錄的過程。

作爲一個地區的想法可以看到一個地區的所有地區和代表,區可以看到他們的代表。代表只能看到自己。

我有表:

ID   ParentId   Name 
------------------------------------------------------- 
1    Null    Corporate HQ 
2    1     South Region 
3    1     North Region 
4    1     East Region 
5    1     West Region 
6    3     Chicago District 
7    3     Milwaukee District 
8    3     Minneapolis District 
9    6     Gold Coast Dealer 
10   6     Blue Island Dealer 

如何我這樣做:

CREATE PROCEDURE GetPositions 
    @id int 
AS 
BEGIN 
    --What is the most efficient way to do this-- 
END 
GO 

例如,對於@id = 3預期的結果,我希望回到:

3, 6, 7, 8, 9, 10 

我很感激任何幫助或想法。

+1

預期結果會是什麼? –

+0

我更新了問題以顯示預期結果。 – JDBennett

回答

6

你可以通過遞歸CTE做到這一點:

DECLARE @id INT = 3; 

WITH rCTE AS(
    SELECT *, 0 AS Level FROM tbl WHERE Id = @id 
    UNION ALL 
    SELECT t.*, r.Level + 1 AS Level 
    FROM tbl t 
    INNER JOIN rCTE r 
     ON t.ParentId = r.ID 
) 
SELECT * FROM rCTE OPTION(MAXRECURSION 0); 

ONLINE DEMO

+0

這是完美的!只是出於好奇 - 這對於大量的記錄會有很好的表現。即比如說我有50K +記錄,Id是公司(頂級)父母。這將如何保持? – JDBennett

+0

通常,遞歸CTE在大型表上不能很好地擴展。至於一切,測試! –

0

假設你在一個合理的現代版本的SQL Server,你可以使用HIERARCHYID數據類型有一點點一點點的潤滑脂。首先,在設置:

alter table [dbo].[yourTable] add [path] hierarchyid null; 

接下來,我們將填充新列:

with cte as (
    select *, cast(concat('/', ID, '/') as varchar(max)) as [path] 
    from [dbo].[yourTable] 
    where [ParentID] is null 

    union all 

    select child.*, 
     cast(concat(parent.path, child.ID, '/') as varchar(max)) as [path] 
    from [dbo].[yourTable] as child 
    join cte as parent 
     on child.ParentID = parent.ID 
) 
update t 
set path = c.path 
from [dbo].[yourTable] as t 
join cte as c 
    on t.ID = c.ID; 

這僅僅是一個沼澤標準遞歸表與代表層次結構中計算列表達式。這是困難的部分。現在,你的程序可以是這個樣子:

create procedure dbo.GetPositions (@id int) as 
begin 
    declare @h hierarchyid 
    set @h = (select Path from [dbo].[yourTable] where ID = @id); 

    select ID, ParentID, Name 
    from [dbo].[yourTable] 
    where Path.IsDescendentOf(@h) = 1; 
end 

所以,包裹起來,你正在與HIERARCHYID做的是存儲沿襲給定行,這樣你就不必在計算它在選擇時間飛行。