来自多对多表

时间:2016-10-17 17:45:03

标签: sql recursion many-to-many

在As到Bs的多对多映射表中,假设有一个初始条件f(A, B) -> bool,该映射表中的一些(A,B)对满足。

问题是选择所有对中,其中对中的A出现在满足条件的集合中,或者对中的B出现在满足条件的集合中。然后继续扩展选择集,直到不再添加不同的对,这样最后,选择包含所有可以“走”到满足初始条件的对的对。

示例:

A_id    B_id
------------
 A1      B1
 A1      B3
 A2      B1
 A2      B2

假设对(A2,B1)和(A2,B2)满足f,并且对(A1,B1)和(A1,B3)不满足。我需要返回的集合包含所有四对,因为B1出现在满足f的集合中(所以我们包括(A1,B1))和A1现在出现在增长集合中(所以我们包括(A1) ,B3))。

这种服务器端的正确方法是什么?在服务器上执行它比在客户端上存储一些中间结果并在几个“增量”查询中执行递归更好吗?当行数非常大时,答案如何变化?

(我需要在SQL Server中执行此操作,但这不是问题所必需的。)

伪查询语言的示例解决方案:

declare @results table(A_id, B_id)

-- initial set, satisfying the condition
insert into @results -- adds (A2, B1) and (A2, B2)
select A_id, B_id from mapping m where f(A_id, B_id) == true

-- first round of recursion
insert into @results
select m.A_id, r.B_id from mapping m -- adds (A1, B1)
join @results r on r.B_id = m.B_id
insert into @results
select r.A_id, m.B_id from mapping m
join @results r on r.A_id = m.B_id

-- second round of recursion
insert into @results
select m.A_id, r.B_id from mapping m
join @results r on r.B_id = m.B_id
insert into @results
select r.A_id, m.B_id from mapping m -- adds (A1, B3)
join @results r on r.A_id = m.B_id

1 个答案:

答案 0 :(得分:0)

如果添加第三列,在表中给出f值,则可以使用此查询。

with CTE as 
(
    Select A_ID as Node, Path = CAST(a_id as nvarchar(max))
    from Link
    where f = 1

    UNION

    Select B_ID as Node, Path = CAST(B_ID as nvarchar(max))
    from Link
    where f = 1

    UNION ALL

    Select L.B_ID, CTE.Path + '-' + L.B_ID
    from CTE inner join Link L ON CTE.node = L.A_ID
    where CTE.path not like '%' + L.B_ID +'%'

    UNION ALL

    Select L.A_ID, CTE.Path + '-' + L.A_ID
    from CTE inner join Link L ON CTE.node = L.B_ID
    where CTE.path not like '%' + L.A_ID +'%'
)
select distinct Node from CTE