Есть много решений для этого вопроса, у каждого есть свои преимущества и недостатки,
и там не идеал. Это зависит от ваших задач.
Одним из таких решений является закрытие перехода (http://en.wikipedia.org/wiki/Transitive_closure).
Преимущество - очень простые запросы и производительность.
Недостатки - сложность в обслуживании и большой объем из-за денормализации.
F.e. это две таблицы узлов и переходов. \
Первая таблица очевидна, а вторая должна содержать ALL дочерний элемент EVERY . Сам узел должен включать узел с нулевым уровнем.
create table Node (
node_id integer not null,
name varchar(255) null,
constraint PK_NODE primary key (node_id)
)
go
create table Transition (
node_id integer null,
child_id integer null,
levl integer null
)
go
Lvl - уровень является полезным столбцом во многих запросах.
Например, вы можете получить все дочерние элементы любого узла простым запросом:
select
c.node_id,
c.name
from
Transition t,
Node c
where
t.node_id = :id
and t.child_id = c.node_id
and lvl > 0
Конечно, вы должны создать хранимую процедуру или триггер для заполнения и обслуживания таблицы переходов.
Существуют и другие решения (менее дорогие по объему, но более сложные для обновления), но вы можете начать с этого.
Другие СУБД, такие как Oracle, имеют встроенную поддержку запросов дерева (соединяются по пути f.e.), но этот тип запроса имеет ОЧЕНЬ плохую производительность для больших таблиц.