如何避免递归CTE重复锚值

时间:2015-08-09 05:01:46

标签: sql sql-server tsql

我正在使用以下CTE来获得经理和员工的层次结构,我有一个员工的多个经理,在这种情况下,我不希望CTE一次又一次地重复该员工,因为它正在做我的代码 -  getemp()是一个返回employeeid, name and managerID

的简单函数
;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 @Rows=@@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 @Rows=@@ROWCOUNT
    --SELECT @Rows AS Rows
    IF @Rows > 0
    BEGIN
    SELECT  @I = @I + 1;
    END


END

select distinct * from #Temp1
END

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分: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 @Rows=@@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 @Rows=@@ROWCOUNT
    --SELECT @Rows AS Rows
    IF @Rows > 0
    BEGIN
    SELECT  @I = @I + 1;
    END
END
select distinct * from #Temp1
END