链接具有公共ID的关联实体的所有ID

时间:2017-02-24 21:02:49

标签: sql sql-server tsql

ERD只是为了方便起见:

表“位置”中的位置可以通过关联实体“链接位置”

相互链接

假设有一些当前的链接看起来像这样:

location_id_1       location_id_2       active
1                   5                   True
5                   3                   True
2                   6                   True
4                   6                   True
6                   7                   True

我正在尝试编写一个查询,该查询将返回一个列,其中包含可能相互连接的所有ID,即使被一个或多个链接删除/远距离也是如此。因此,1链接到5,3链接到5.由于公共ID为5,1也被删除后链接到3。

所以,在我的查询中,我希望能够决定“Prime位置”,如果你愿意,然后它将返回连接到我的黄金地段的一列中的所有位置ID,直接,或一次或两次或n次移除。

我可以轻松地使用可能发生的第一级链接(参见下面的查询),但是一旦我引入了二级或三级链接,我很难看到除了手动更新我的查询以允许另一个方法之外的其他方式联系程度。

declare  @PrimeLocation int
set @PrimeLocation = 1


Select location_id_1
from [Link Location]
where location_id_1 = @PrimeLocation
or location_id_2 = @PrimeLocation

union 

Select location_id_2
from [Link Location]
where location_id_1 = @PrimeLocation
or location_id_2 = @PrimeLocation

此查询显然只返回“1”和“5”。但是如何让它返回“3”以及其他ID,我是否应该在未来添加另一个链接,可能会从1中删除两次?我是否可以这样做而无需每次都添加我的查询?

因此,如果我的“Prime Location”= 1(或3或5),我的结果集应为:

location_id
1
3
5

如果我的“黄金位置”是2(或4或6或7),我的结果集应为:

location_id
2
4
6
7

提前致谢。

2 个答案:

答案 0 :(得分:0)

好吧,经过一系列试验和阅读递归CTE后,我终于想出了一些对我有用的东西。

一些注意事项:

我必须添加深度列,以便在深度达到一定水平后我可以取消循环。这仍然不理想,因为我希望递归在它完成时取消它,但我不知道这是怎么可能的,因为我的层次结构中没有顶层。换句话说,我的链接不是子链接到父链接,就像我能找到的所有CTE示例一样,最终有一个位置不再有链接。

无论如何,这就是我所做的:

 declare  @PrimeLocation int
 set @PrimeLocation = 1
 ;


 WITH LocationLinks AS
 (
 SELECT location_id_1, location_id_2, 0 as depth
 FROM [Link Location]
 WHERE location_id_1 = @PrimeLocation
 OR location_id_2 = @PrimeLocation

 UNION ALL

 SELECT T1.location_id_1, T1.location_id_2, T2.depth + 1
 FROM [Link Location] T1
 JOIN LocationLinks T2  on T1.location_id_1 = T2.location_id_2 
 or T1.location_id_2 = T2.location_id_1
 WHERE T2.depth <=4

 )

 SELECT *
 INTO #Links
 FROM LocationLinks
 ------Lumping everything into one column-------
 SELECT distinct  location_id_1 
 FROM
 (
     SELECT distinct location_id_1
     FROM #Links

     UNION ALL

     SELECT distinct location_id_2
     FROM #Links
 ) a
 ORDER BY location_id_1

这导致我的预期输出:

 location_id_1
 1
 3
 5

答案 1 :(得分:0)

假设成对中id的顺序没有意义,这将产生所需的结果:

-- Sample data.
declare @LinkLocations as Table ( LocationId1 Int, LocationId2 Int );
insert into @LinkLocations ( LocationId1, LocationId2 ) values
  ( 1, 5 ), ( 5, 3 ), ( 2, 6 ), ( 4, 6 ), ( 6, 7 );
select * from @LinkLocations;

-- Search the links.
declare @PrimeLocationId as Int = 1;
with Locations as (
  select @PrimeLocationId as LocationId,
    Cast( '.' + Cast( @PrimeLocationId as VarChar(10) ) + '.' as VarChar(1024) ) as Visited
  union all
  select LL.LocationId1,
    Cast( '.' + Cast( LL.LocationId1 as VarChar(10) ) + L.Visited as VarChar(1024) )
    from @LinkLocations as LL inner join
      Locations as L on L.LocationId = LL.LocationId2
    where L.Visited not like '%.' + Cast( LL.LocationId1 as VarChar(10) ) + '.%'
  union all
  select LocationId2,
    Cast( '.' + Cast( LL.LocationId2 as VarChar(10) ) + L.Visited as VarChar(1024) )
    from @LinkLocations as LL inner join
      Locations as L on L.LocationId = LL.LocationId1
    where L.Visited not like '%.' + Cast( LL.LocationId2 as VarChar(10) ) + '.%' )
  select LocationId -- , Visited
    from Locations
    option ( MaxRecursion 0 );

您可以在最后Visited中取消注释select,以查看部分内幕。这将正确处理甚至退化的情况,如42, 42将一个id链接到自身。