SQL Server函数用于获取层次结构

时间:2015-05-17 12:24:33

标签: sql sql-server sql-server-2012

我有以下表(master_group)结构:

code    name                      under 

1       National Sales Manager    1
2       regional sales manager    1 
3       area sales manager        2 
4       sales manager             3

如何获得特定行的最终父级,如:

code    name                      under     ultimateparent

1       National Sales Manager    1         1
2       regional sales manager    1         1
3       area sales manager        2         1
4       sales manager             3         1

5 个答案:

答案 0 :(得分:5)

递归cte从top到childs:

with cte as(
  select *, code as ultimate from t where code = under
  union all
  select t.*, c.ultimate from t
  join cte c on c.code = t.under
  where t.code <> t.under
)
select * from cte

对于数据:

create table t (code int, name varchar(100), under int)
insert into t values
(1, 'National Sales Manager', 1),
(2, 'regional sales manager', 1),
(3, 'area sales manager', 2),
(4, 'sales manager', 3),
(5, 'a', 5),
(6, 'b', 5),
(7, 'c', 5),
(8, 'd', 7),
(9, 'e', 7),
(10, 'f', 9),
(11, 'g', 9)

它生成输出:

code    name                    under   ultimate
1       National Sales Manager  1       1
5       a                       5       5
6       b                       5       5
7       c                       5       5
8       d                       7       5
9       e                       7       5
10      f                       9       5
11      g                       9       5
2       regional sales manager  1       1
3       area sales manager      2       1
4       sales manager           3       1

小提琴http://sqlfiddle.com/#!6/17c12e/1

答案 1 :(得分:2)

您可以使用递归CTE遍历树,然后为每个代码选择最高级别:

with cte as (
      select mg.code, mg.name as name, mg.under as under, mg.under as parent, 1 as lev
      from master_group mg
      union all
      select mg.code, mg.name, mg.under, cte.under as parent, cte.lev + 1
      from master_group mg join
           cte
           on mg.under = cte.code
      where cte.under is not null and cte.under <> mg.code
     )
select code, name, under, parent as ultimateparent
from (select cte.*, max(lev) over (partition by cte.code) as maxlev
      from cte
     ) t
where lev = maxlev;

Here是一个SQL小提琴。

答案 2 :(得分:1)

当它是最高记录时,我会将NULL设置为(在我的示例中为ParentId)。有了这个假设,这是一个解决方案

WITH Result AS
(
    SELECT Id, ParentId, Name, Id as [Top] FROM
    sample
    where  ParentId IS NULL 
    UNION ALL 
    SELECT s.Id, s.ParentId, s.Name, [Top]
    FROM sample s INNER JOIN Result R ON s.ParentId = R.Id
)

http://sqlfiddle.com/#!6/13b9d/14

答案 3 :(得分:0)

我建议你使用这样的递归函数:

CREATE FUNCTION dbo.parentID (@code int)
RETURNS int AS
BEGIN
    DECLARE @ResultVar int
    SELECT @ResultVar = (SELECT under FROM master_group WHERE code = @code)
    IF @ResultVar <> @code 
    BEGIN
        SELECT @ResultVar = dbo.parentID(@ResultVar)
    END
    RETURN @ResultVar
END
GO

使用它是这样的:

SELECT *, 
       dbo.parentId(code) AS ultimateparent
FROM master_group

答案 4 :(得分:-1)

我将从另一个答案中无耻地窃取数据设置并演示如何使用hierarchyid执行此操作:

create table t (code int, name varchar(100), under int)
insert into t values
    (1, 'National Sales Manager', null),
    (2, 'regional sales manager', 1),
    (3, 'area sales manager', 2),
    (4, 'sales manager', 3),
    (5, 'a', null),
    (6, 'b', 5),
    (7, 'c', 5),
    (8, 'd', 7),
    (9, 'e', 7),
    (10, 'f', 9),
    (11, 'g', 9);

with cte as (
    select code, name, under as parentCode, code as ultimateParent, cast('/' + cast(code as varchar) + '/' as nvarchar(max)) as h
    from t
    where under is null

    union all

    select child.code, child.name, child.under as ParentCode, parent.ultimateParentCode, cast(parent.h + cast(child.code as varchar) + '/' as nvarchar(max))
    from t as child
    join cte as parent
        on child.under = parent.code
), hier as (
select code, name, parentCode, ultimateParentCode, cast(h as hierarchyid) as h
from cte
)
select code, name, parentCode, ultimateParentCode, h.ToString(), h.GetAncestor(h.GetLevel()-1).ToString()
from hier

请记住,递归CTE只需要进行一次(或者在数据更改时)。我正在做的一点是,一旦你有一个计算的hierarchyid(你可以存储在行中,顺便说一句),很容易回答你在hierarchyid上使用方法调用提出的问题(如果你想要的话可​​能还有一个连接)找回祖先的信息。)