Я не думаю, что здесь есть необходимость в рекурсии, поскольку решение Барри Брауна кажется адекватным. Если вам нужна группа, чтобы иметь возможность быть членом группы, то метод обхода дерева, предложенный Dems, работает хорошо. Вставки, удаления и обновления довольно просты с этой схемой, и извлечение всей иерархии осуществляется с помощью одного выбора.
Я бы предложил включить поле parent_id в таблицу group_members (при условии, что это точка, в которой возникают ваши рекурсивные отношения). В редакторе навигации я создал таблицу узлов следующим образом:
tbl_nodes
----------
node_id
parent_id
left
right
level
...
Мой редактор создает иерархически связанные объекты из класса узла C #
class node {
public int NodeID { get; set; }
public Node Parent { get; set; }
public int Left { get; set; }
public int Right { get; set; }
public Dictionary<int,Node> Nodes { get; set; }
public int Level {
get {
return (Parent!=null) ? Parent.Level+1 : 1;
}
}
}
Свойство Nodes содержит список дочерних узлов. Когда бизнес-уровень загружает иерархию, он исправляет родительские / дочерние отношения. Когда навигационный редактор сохраняет, я рекурсивно устанавливаю значения свойств left и right, затем сохраняю в базу данных. Это позволяет мне выводить данные в правильном порядке, что означает, что я могу установить родительские / дочерние ссылки во время поиска вместо того, чтобы делать второй проход. Также означает, что все, что требуется для отображения иерархии (например, отчет), может легко вывести список узлов в правильном порядке.
Без поля parent_id вы можете получить цепочку хлебных крошек к текущему узлу с помощью
select n1.*
from nodes n1, nodes n2
where d1.lft <= d2.lft and d1.rgt >= d2.rgt
and d2.id = @id
order by lft;
где @id - идентификатор интересующего вас узла.
Довольно очевидные вещи, на самом деле, но они применяются к таким элементам, как членство во вложенных группах, которые могут быть неочевидны, и, как говорили другие, устраняют необходимость замедлять рекурсивный SQL.