2011-09-18 53 views
3

在另一個question我問了關於存儲在SQL Server數據庫的表中的分層數據。我發現了一種使用GraphViz可視化整個層次結構的方法,在T-SQL和Powershell中有一些管道。如何僅可視化層次中節點的後代,祖先和自我?

我想使用這樣的可視化來調試使用類似數據的應用程序。對於小示例層次結構來說,可視化一切都很好。但是,在數千人的等級中,這是壓倒性的。

當我調試我的應用程序時,我通常只查看與給定節點相關的一小組節點。目前,對於給定節點而言,唯一與我有關的相關節點是後代和祖先,以及節點本身。

所以,我想要一種方法來只可視化層次結構中作爲給定節點的後代,祖先或自身的節點。

以下語句將在鏈接問題中創建示例數據庫和表。

CREATE DATABASE HierarchyTest; 
GO 

USE HierarchyTest; 
GO 

CREATE TABLE NodeHierarchy (
    PK_NodeID INT NOT NULL 
    CONSTRAINT PK_NodeHierarchy PRIMARY KEY, 
    FK_ParentNodeID INT NULL 
    CONSTRAINT FK_NodeHierarchy_NodeHierarchy FOREIGN KEY 
     REFERENCES NodeHierarchy(PK_NodeID), 
    Name NVARCHAR(255) NOT NULL 
); 

以下語句使用國家,城市和場所的層次結構的修改版本填充表格。英國現在是根節點,並且有更多節點代表着名的英國場館。

INSERT INTO NodeHierarchy(PK_NodeID, FK_ParentNodeID, Name) 
VALUES 
    (1, 18, N'Scotland'), 
    (2, 1, N'Glasgow'), 
    (3, 1, N'Edinburgh'), 
    (4, 1, N'St Andrews'), 
    (5, 2, N'The Barrowlands'), 
    (6, 2, N'The Cathouse'), 
    (7, 2, N'Carling Academy'), 
    (8, 2, N'SECC'), 
    (9, 2, N'King Tut''s Wah-Wah Hut'), 
    (10, 3, N'Henry''s Cellar Bar'), 
    (11, 3, N'The Bongo Club'), 
    (12, 3, N'Sneaky Pete''s'), 
    (13, 3, N'The Picture House'), 
    (14, 3, N'Potterrow'), 
    (15, 4, N'Aikman''s'), 
    (16, 4, N'The Union'), 
    (17, 4, N'Castle Sands'), 
    (18, NULL, N'United Kingdom'), 
    (19, 15, N'Upstairs'), 
    (20, 15, N'Downstairs'), 
    (21, 16, N'Venue 1'), 
    (22, 16, N'Venue 2'), 
    (23, 18, N'England'), 
    (24, 23, N'Manchester'), 
    (25, 24, N'Apollo Theatre'), 
    (26, 18, N'Liverpool'), 
    (27, 26, N'Cavern Club'); 

以下圖像是鏈接問題中列出的Powershell腳本generate-graph.ps1的輸出。如果堆棧溢出縮小尺寸版本看起來很難看,請看full-size image

Visualization of entire hierarchy generated by GraphViz

我只想看到聖安德魯斯後代和祖先如何與它。該圖包含許多與這些關係無關的信息,因此更難以閱讀。當我將我的等級擴展到全球數千個覆蓋城市和場館的節點時,完全可視化幾乎變得毫無用處。

Freemind我畫的,我想看到什麼,而不是粗圖:

Hand-constructed diagram of descendants, anscestors, and self of St Andrews

我如何提取僅是相關的聖安德魯斯數據,以便我可以給GraphViz的?

+1

這是一個危險的問題。我已經有了自己的解決方案,但我想分享它解決的問題。我會盡快發佈我自己的解決方案。 –

+0

你使用的是SQL Server 2008嗎? –

+0

我正在使用SQL Server 2008.我沒有忘記發佈我的解決方案,順便說一句;我剛剛很忙! –

回答

0

層次結構的自我引用表示對於像以下這樣的作業有點笨重 - 您只想選擇一個分支,因此您需要以未知次數遞歸地連接到目標表。很可能,但是任何時候我在SQL Server中使用層次結構時,我都會直接跳到HierarchyId

我不知道我們是否可以遞歸在同一時間看都樹;一個天真的方法失敗了,所以我會提出一個更簡單的選擇。

您已擁有當前節點。獲取該節點的子節點,然後獲取該節點的父節點。聯合他們,你就完成了。在SQL中執行遞歸連接的最簡單方法是使用Common Table Expressions

DECLARE @nodeid INT = 4 
DECLARE @nodes TABLE (NodeID INT) 

; WITH Parents (NodeID) AS 
(
    -- get the parent of the current node 
    SELECT FK_ParentNodeID FROM NodeHierarchy WHERE PK_NodeID = @nodeId 
     -- not sure if 'null' is a valid parent, but I'm assuming not 
     AND FK_ParentNodeID IS NOT NULL 
    UNION ALL 
    -- recursively get the parents of the parent 
    SELECT FK_ParentNodeID FROM NodeHierarchy 
     INNER JOIN Parents ON PK_NodeID = NodeID 
     WHERE FK_ParentNodeID IS NOT NULL  
) 
INSERT @nodes SELECT NodeID FROM Parents 

; WITH Childs (NodeID) AS 
(
    -- selecting the current node 
    SELECT PK_NodeID FROM NodeHierarchy WHERE PK_NodeID = @nodeId 
    UNION ALL 
    -- recursively select the children of the branch 
    SELECT PK_NodeID FROM NodeHierarchy 
     INNER JOIN Childs ON FK_ParentNodeID = NodeID 
) 
INSERT @nodes SELECT NodeID FROM Childs 

SELECT * FROM @nodes 

現在根據你前面的問題,您只需從現有的視圖中進行選擇。

SELECT Node, Label FROM NodeLabels 
WHERE Node IN (SELECT NodeID FROM @nodes) 

SELECT Parent, Child FROM Edges 
WHERE Parent IN (SELECT NodeID FROM @nodes) 
0

我不認爲你注意這裏用的結合,它是一種更簡單:

declare @nodeid int, @parentID int 
select @nodeid = PK_NodeID, @parentID = FK_ParentNodeID 
    from NodeHierarchy where name = 'St Andrews' 

select PK_NodeID, FK_ParentNodeID, Name 
    from NodeHierarchy 
    where PK_NodeID in (@nodeid, @parentID) 
    or FK_ParentNodeID = @nodeid 

當然,你可以把它放在一個表函數,使其一般。

相關問題