2015-05-17 2 views
3

Я следующей таблице (master_group) структуры:функция SQL Server, чтобы получить верхний родительский уровень в иерархии

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 
+0

@MartinDavidValentinoSiagian: Я упомянул, что в вопросе, вторая структура таблицы. –

ответ

4

рекурсивные CTE происходит от верхней части к Чайлдс:

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

+0

Пожалуйста, взгляните на эту скрипку: http://sqlfiddle.com/#!6/f9981e/2/0. Я немного изменил данные. У меня 44 записи, но она показывает только 39. Я не мог найти, в чем проблема. –

+1

@NitinKabra, в конце концов, у вас есть длинные иды, которые не являются родителями или детьми какого-либо другого ряда. –

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.

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 
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

-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 необходимо выполнить только один раз (или при изменении данных). То, что я делаю, заключается в том, что, как только вы вычислена иерархия (которую вы можете сохранить в строке, кстати), легко ответить на вопрос, который вы задаете, с вызовами метода на иерархии (и, возможно, соединение, если вы хотите чтобы вернуть информацию прародителя).

Смежные вопросы