2017-02-24 27 views
-1

ERD只是爲了輕鬆vizualise:鏈接來自關聯實體的具有共同ID的所有ID

從表位置的「位置」可以通過關聯實體「鏈接位置」

進行相互鏈接

假設有看起來像這樣的一些當前鏈接:

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連接。由於5的公共ID,因此1與3一起被移除。

因此,在我的查詢中,我希望能夠決定「黃金位置」,如果您願意,然後它將返回連接到我的黃金位置的所有位置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,我是否應該在未來添加另一個鏈接到3,然後可能會從1中刪除兩次?我可以做到這一點,而不必每次都添加到我的查詢中嗎?

所以,如果我的 「素位置」= 1(或3或5)我的結果集應該是:

location_id 
1 
3 
5 

如果我的 「黃金地段」 爲2(或4或6或7)我的結果集應該是:

location_id 
2 
4 
6 
7 

在此先感謝。

+1

這看起來像一個遞歸CTE將是必要的,我相當肯定這個問題幾乎相同的版本是在過去幾個月發佈;您可能需要花點時間嘗試一些不同的搜索關鍵字,看看您是否可以找到它。 –

+0

[This](http://stackoverflow.com/a/15081353/92546)答案演示了一種通過遞歸漫遊關係,同時避免無限循環的方式。訣竅是跟蹤你去過的地方並終止這些遞歸。 – HABO

回答

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鏈接到自身。

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 
相關問題