如何使用SQL Server 2008在CTE递归内增加变量

时间:2017-12-08 21:14:45

标签: sql sql-server sql-server-2008 recursion common-table-expression

我有以下代码,我想用CTE进行递归并在内部递增变量,以便递归可以使用它来执行子查询。

WITH cte as
(
    select @layer as layers,
    case when exists(select * from #table where layer=@layer and string in ('abc','xyz)) then 10 else 0 end 
    union all
    select layers + 1, total
    from cte
    where layers + 1<4 -- 4 is a max number that is unknown and given by the user
)select * from cte

#table具有以下结构,但数据量是动态的

string     layer
abc        1
xyz        1
abc        2
xyz        2

所以在第1层,如果它有&#39; abc&#39;或者&#39; xyz&#39;它将具有10分,第2层也会发生相同的事情,直到用户给出的最大层为止。我想从递归中得到点和相应的级别。虽然循环和光标是禁止的。我在递归中增加@layer时遇到了麻烦。有什么建议吗?感谢

1 个答案:

答案 0 :(得分:2)

我从来没有看到过递归中使用的变量,但我认为你可以用理货表做你想做的事。

if object_id('tempdb..#table') is not null drop table #table

create table #table (string varchar(64), layer int)
insert into #table
values
('abc',1),
('abc',2),
('xyz',2),
            --missing layer 3
            --missing layer 4
('fgh',5),  --not in the abc or xyz clause
('abc',6),
('xyz',7)   --greate than the max passed in via @layer




declare @layer int = 6

;WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )

select
    N as Layer
    ,case when max(layer) is not null then 10 else 0 end
from 
    cteTally
    full join #table 
    on N = layer and string in ('abc','xyz')
where N <= @layer
group by N
order by N

如果你真的开始使用递归,如果传入的@layer或最大数量很大,这可能会慢得多,那么这就是你将如何实现这一点。

declare @layer int = 6

;with cte as(
    select 
        1 as layer
        ,total = case when exists(select * from #table t2 where t2.layer=layer and t2.string in ('abc','xyz')) then 10 else 0 end
    union all
    select 
        layer + 1
        ,total = case when exists(select * from #table t2 where t2.layer=c.layer + 1 and t2.string in ('abc','xyz')) then 10 else 0 end
    from cte c
    where layer < @layer)

select distinct 
    layer
    ,total = max(total)
from cte
group by layer
order by layer