2017-08-01 71 views
0

我有一張表,它通過將兩個「節點」鏈接在一起來創建路徑。遞歸CTE返回路徑中的所有連接節點

Node 
----------- 
Id - Primary Key 
Name 
etc... 


Path 
------ 
Id - Primary Key 
From - FK to Node 
To - FK to Node 

所以這個路徑:

W --- X --- Y --- Z 

可以建這樣的:

Node 
Id Name 
--- ----- 
1 W 
2 X 
3 Y 
4 Z 
5 A 
6 B 
7 C 


Path 
Id From  To 
--- ------- ------- 
1 1  2 
2 2  3 
3 3  4 
4 6  7 

我想出了給定任何節點ID遞歸CTE查詢,遍歷的路徑和返回所有涉及的「路徑」。

declare @nodeId = 2 
;WITH cte AS (

    -- ANCHOR 
    -- Find one path involving Node 
    SELECT top 1 p.*, 0 as [Seq] FROM dbo.Path p WHERE [From] = @nodeId or [To] = @nodeId 

    union all 

    -- go left 
    select leftPath.*, cte.[Seq] - 1 as [Seq] 
    from [Path] leftPath 
    join cte on cte.[From] = leftPath.[To] and cte.[Seq] <= 0 

    union all 

    -- go right 
    select rightPath.*, cte.[Seq] + 1 as [Seq] 
    from [Path] rightPath 
    join cte on cte.[To] = rightPath.[From] and cte.[Seq] >= 0 
) 

SELECT cte.Id, cte.Seq, cte.From, cte.To 
FROM cte 
order by [Seq] 

因此,這將返回所有路徑 -

Path 
Id Seq From  To 
--- --- ------- ------- 
1 -1 1  2 
2 0 2  3 
3 1 3  4 

但我怎麼能寫出給定的節點ID之一的查詢,穿越的路徑,左,右,並返回所有不同(有序)涉及的節點?

Id Name 
    --- ----- 
    1 W 
    2 X 
    3 Y 
    4 Z 
+0

您的查詢似乎沒有工作,例如'description'不存在。請解決這個問題,我會看看http://rextester.com/DEVHNG47817 –

+0

固定;請參閱:http://rextester.com/live/QBDQ1655 – user210757

+0

該查詢不匹配您的輸出。不否定'Seq' –

回答

0

我想說的是這樣的:

DECLARE @nodeId int = 2; 

select 
* 
from Node t1 
inner join Path t2 
on t1.Id = t2.[From] or t1.Id = t2.[To] 
where t1.Id = @nodeId 
order by t1.Id 

我知道,上面的查詢不能解決你的問題,但是,這個查詢你得到了相同的結果比用CTE和更簡單。從這個查詢中查詢結果如果查詢還沒有結果,你期望的結果是什麼。

但我明白這不是你想要的。爲此,我需要一個完整的結果示例,我讀的最後一個段落是表節點。 ¿?

+0

你是對的更復雜的樣本,否則'選擇*從節點order by id'返回需要的輸出。 –

+0

已更新的問題。添加了3個新節點和一個新路徑。所以現在有2條路徑 - W-X-Y-Z和B-C。運行原始查詢寬度nodeid 2會產生與以前相同的結果 - 整個路徑nodeid 2(名爲X)參與其中。我的查詢返回圖的邊,我希望它返回頂點。 – user210757

0

這會返回您想要的結果,但對於@nodeId int = 5;的情況,它不返回任何內容,因爲沒有與該節點關聯的路徑。

見我從cte.[From]得到Name's,然後從最後 ID cte.[To]

我添加源再添Name,以確保訂單是您在輸出顯示的一個。否則因爲屬於同一行的最後兩個Name's可能會有倒序。

SQL DEMO

;WITH cte AS (

    -- ANCHOR 
    -- Find one path involving Node 
    SELECT top 1 p.*, 0 as [Seq] FROM dbo.Path p WHERE [From] = @nodeId or [To] = @nodeId order by [From] desc 

    union all 

    -- go left 
    select leftPath.*, cte.[Seq] - 1 as [Seq] 
    from [Path] leftPath 
    join cte on cte.[From] = leftPath.[To] and cte.[Seq] <= 0 

    union all 

    -- go right 
    select rightPath.*, cte.[Seq] + 1 as [Seq] 
    from [Path] rightPath 
    join cte on cte.[To] = rightPath.[From] and cte.[Seq] >= 0 
) 

SELECT 'A' as [Source], cte.Id, cte.Seq, cte.[From], cte.[To], Node.[Name] 
FROM cte 
JOIN Node 
    ON cte.[From] = Node.[Id] 
UNION 
SELECT 'B' as [Source], cte.Id, cte.Seq, cte.[From], cte.[To], Node.[Name] 
FROM cte 
JOIN Node 
    ON cte.[To] = Node.[Id] 
WHERE cte.id = (SELECT Max(Id) FROM cte) 

order by [Source], [Seq] 

OUTPUT

@nodeId int = 1 to 4 same result: 

enter image description here

@nodeId int = 6 to 7 same result: 

enter image description here

如果你把前面的查詢也CTE,並呼籲step2你可以有你的願望格式是這樣的:

SELECT ROW_NUMBER() OVER (ORDER BY [Source], [Seq]) as [Id], 
     Name 
FROM step2 

最終輸出

enter image description here