2015-08-09 61 views
0

我正在使用以下CTE来获取经理和员工的层次结构,我有一个员工的多个经理,在这种情况下,我不希望CTE重复为该员工一次又一次因为它是做在我的代码 - getemp()是一个简单的函数返回employeeid, name and managerID如何避免递归CTE重复定位值

;With hierarchy as 
(
select [Level]=1 , * from dbo.getemp() where managerid = 1 
union all 
select [Level]+1 , e.* from getemp() e 
join hierarchy h on h.employeeid = e.managerid 

) 
Select * from hierarchy 

编辑后 - 以下办法为我工作。 CTE有可能吗?

SET NOCOUNT ON; 
    DECLARE @Rows int 


    SELECT [Level] = ISNULL(1,0), 
     employeeid = ISNULL(employeeid, 0), 
     empname = CAST(empname as varchar(10)), 
     managerid = ISNULL(managerid,0) 
     into #Temp1 
     from dbo.getemp() as a1 
     where a1.managerid = @Top1 
     --select * from #Temp1 
     SELECT @[email protected]@ROWCOUNT 

     DECLARE @I INT = 2; 
     while @Rows > 0 
     BEGIN 

    Insert into #Temp1 
    select @I as Level, b.employeeid, b.empname, b.managerid from #Temp1 as e 
    inner join (select [employeeid], [empname], [managerid] from dbo.GetEmp())  as b on b.managerid = e.employeeid 
    where e.Level = @I - 1 
    and not exists (
    SELECT 1 FROM #Temp1 t 
    WHERE b.employeeid = t.employeeid 
    AND b.managerid = t.managerid); 
    SELECT @[email protected]@ROWCOUNT 
    --SELECT @Rows AS Rows 
    IF @Rows > 0 
    BEGIN 
    SELECT @I = @I + 1; 
    END 


END 

select distinct * from #Temp1 
END 
+0

如果员工有几个管理人员,其中之一应在经理ID被退回? –

+0

@JamesZ如果员工有两个经理,那么它应该返回两个managerID的行。但是对于下一次递归,它应该只考虑员工一次而不是两次。 – vishakha

+0

示例数据和预期结果将会有所帮助。 CTE的一个问题是,递归查询无法访问除最近添加的行之外的其他任何内容。如果你需要访问先前处理过的行的所有_all_,那么你可能需要使用'WHILE'循环并将结果组装到一个临时表中,直到“@@ ROWCOUNT = 0”。 – HABO

回答

0

无法找到使用CTE的解决方案,所以我用了while循环,以避免重复锚,这里的代码..

DECLARE @Rows int 
    SELECT [Level] = ISNULL(1,0), 
     employeeid = ISNULL(employeeid, 0), 
     empname = CAST(empname as varchar(10)), 
     managerid = ISNULL(managerid,0) 
     into #Temp1 
     from dbo.getemp() as a1 
     where a1.managerid = @Top1 
     --select * from #Temp1 
     SELECT @[email protected]@ROWCOUNT 

     DECLARE @I INT = 2; 
     while @Rows > 0 
     BEGIN 

    Insert into #Temp1 
    select @I as Level, b.employeeid, b.empname, b.managerid from #Temp1 as e 
    inner join (select [employeeid], [empname], [managerid] from dbo.GetEmp())  as b on b.managerid = e.employeeid 
    where e.Level = @I - 1 
    and not exists (
    SELECT 1 FROM #Temp1 t 
    WHERE b.employeeid = t.employeeid 
    AND b.managerid = t.managerid); 
    SELECT @[email protected]@ROWCOUNT 
    --SELECT @Rows AS Rows 
    IF @Rows > 0 
    BEGIN 
    SELECT @I = @I + 1; 
    END 
END 
select distinct * from #Temp1 
END 
0

既然你有几个管理人员,这意味着人们也可以在几个不同的层次,由于在经理有不同的等级,你可以只需要为每个分支的最低水平像这样的东西:

;With hierarchy as 
(
    select [Level]=1 , * from dbo.getemp() where managerid = 1 
    union all 
    select [Level]+1 , e.* from getemp() e 
    join hierarchy h on h.employeeid = e.managerid 
) 

Select min(Level) as Level, employeeid, name, managerid from hierarchy 
group by employeeid, name, managerid 

使用函数在每次递归中返回所有员工可能不是关于性能的最佳解决方案,尤其是如果它不是内联函数。您可能想考虑使用例如临时。表,如果你不能直接读取表。

+0

感谢您的答案,我们有系统中现有的功能,我需要使用...为了问这个问题,我给了emp经理场景..与您的答案仍然CTE将一次又一次地为同一员工递减..这是我想要避免..我不需要'级别'的任何特定原因,如果删除,有助于获得正确的查询 – vishakha

+0

@vishakha如果您将数据加载到临时数据中。表,你还在使用这个功能吗?为什么你试图避免同一个人被多次提取? –

+0

@ JamesZ我的坏..我不明白你在说什么..会尝试使用临时表 – vishakha