有没有办法在SQL Server中检测分层查询中的循环?

ama*_*u96 3 t-sql sql-server connect-by hierarchy

在Oracle中,我们可以使用该函数CONNECT_BY_ISCYCLE来检测分层查询中的循环.我尝试在SQL Server中执行相同的操作.有没有办法做到这一点?

非常感谢!

Dav*_*itz 8

连接记录ID /根据记录的ROW_NUMBERs构建位图,并根据列表/位图验证每个新记录

create table t (id int,pid int)
insert into t values (1,3),(2,1),(3,2)
Run Code Online (Sandbox Code Playgroud)

名单

识别周期

with cte (id,pid,list,is_cycle) 
as
(
    select      id,pid,',' + cast (id as varchar(max))  + ',',0
    from        t
    where       id = 1

    union all

    select      t.id,t.pid,cte.list + cast (t.id as varchar(10)) +  ',' ,case when cte.list like '%,' + cast (t.id as varchar(10)) + ',%' then 1 else 0 end
    from        cte join t on t.pid = cte.id
    where       cte.is_cycle = 0
)
select      *
from        cte
where       is_cycle = 1
Run Code Online (Sandbox Code Playgroud)
id  pid list        is_cycle
--  --- ----        --------
1   3   ,1,2,3,1,   1
Run Code Online (Sandbox Code Playgroud)

使用循环遍历完整图形

with cte (id,pid,list) 
as
(
    select      id,pid,',' + cast (id as varchar(max))  + ','
    from        t
    where       id = 1

    union all

    select      t.id,t.pid,cte.list + cast (t.id as varchar(10)) +  ',' 
    from        cte join t on t.pid = cte.id
    where       cte.list not like '%,' + cast (t.id as varchar(10)) + ',%'
)
select      *
from        cte
Run Code Online (Sandbox Code Playgroud)
id  pid list
1   3   ,1,
2   1   ,1,2,
3   2   ,1,2,3,
Run Code Online (Sandbox Code Playgroud)

位图

ID应该是以1开头的数字序列.
如有必要,使用ROW_NUMBER生成它.

识别周期

with cte (id,pid,bitmap,is_cycle) 
as
(
    select      id,pid,cast (power(2,id-1) as varbinary(max)) ,0
    from        t
    where       id = 1

    union all

    select      t.id,t.pid,cast (cte.bitmap|power(2,t.id-1) as varbinary(max)),case when cte.bitmap & power(2,t.id-1) > 0 then 1 else 0 end
    from        cte join t on t.pid = cte.id
    where       cte.is_cycle = 0
)
select      *
from        cte
where       is_cycle = 1
Run Code Online (Sandbox Code Playgroud)
id  pid bitmap      is_cycle
1   3   0x00000007  1
Run Code Online (Sandbox Code Playgroud)

使用循环遍历完整图形

with cte (id,pid,bitmap) 
as
(
    select      id,pid,cast (power(2,id-1) as varbinary(max))
    from        t
    where       id = 1

    union all

    select      t.id,t.pid,cast (cte.bitmap|power(2,t.id-1) as varbinary(max))
    from        cte join t on t.pid = cte.id
    where       cte.bitmap & power(2,t.id-1) = 0
)
select      *
from        cte
Run Code Online (Sandbox Code Playgroud)
id  pid bitmap
1   3   0x00000001
2   1   0x00000003
3   2   0x00000007
Run Code Online (Sandbox Code Playgroud)