Как визуализировать только потомков, предков и себя узла в иерархии? - PullRequest
3 голосов
/ 18 сентября 2011

В другом вопросе Я спросил о визуализации иерархических данных, хранящихся в таблице в базе данных 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, указанный в связанном вопросе. Если версия уменьшенного размера Stack Overflow выглядит некрасиво, посмотрите на полноразмерное изображение .

Visualization of entire hierarchy generated by GraphViz

Я хочу видеть только то, как потомки и предки святого Андрея относятся к этому. Диаграмма содержит много информации, не относящейся к этим отношениям, и поэтому ее труднее читать. Когда я масштабирую свою иерархию до тысяч узлов, охватывающих города и места в мире, полная визуализация становится практически бесполезной.

В Freemind Я нарисовал грубую диаграмму того, что я хотел бы видеть вместо:

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

Как извлечь только те данные, которые имеют отношение к Сент-Эндрюсу, чтобы я мог передать их в GraphViz?

Ответы [ 2 ]

0 голосов
/ 07 февраля 2012

Я не думаю, что вы обращаете внимание на использование объединения здесь, это более простой способ:

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

Конечно, вы можете поместить его в табличную функцию, чтобы сделать ее общей.

0 голосов
/ 04 октября 2011

Самореференциальное представление иерархии немного неуклюже для таких заданий, как - вы хотите выбрать только одну ветвь, поэтому вам нужно будет рекурсивно присоединяться к целевой таблице неизвестное количество раз.Очень возможно, но всякий раз, когда я работаю с иерархиями в SQL Server, я сразу перехожу к HierarchyId .

. Не знаю, сможем ли мы рекурсивно просмотреть оба up и вниз дерево одновременно;Наивный подход терпит неудачу для меня, поэтому я представлю более простую альтернативу.

У вас уже есть текущий узел.Получить детей этого узла, а затем получить родителей этого узла.Объедините их, и все готово.И самый простой способ сделать рекурсивные объединения в SQL с помощью Общих табличных выражений .

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)
...