Как заполнить дерево?
В БД данные храню в такой форме:
ID Name ParentID
1 A 0
2 B 5
3 C 0
4 D 6
5 E 3
6 F 5
(ID не обязательно идут с шагом 1)
То есть по этой таблице получается такое дерево:
.A -
.C +
...|-E +
.......|-B
.........|-F+
.............|-D
Вот теперь сам трабл.
У меня есть два списка с разными системами заполения. На данный момент меня интересует список, который заполняется таки образом
1 A
1 C
2 E
3 D
3 F
4 D
то есть цифрами устанавливается отступ.
вот еще один пример:
1
.2
..3
1
.2
..3
(для наглядности я сделал отступы)
Тут получится дерево с двумя корнями.
Я никак не могу придумать нормальную систему, по которой я данные из таблицы смог бы переформатироваться в вышепреведенную форму.
У меня есть деревовидный список, который надо заполнить данными из БД.
В БД данные храню в такой форме:
ID Name ParentID
1 A 0
2 B 5
3 C 0
4 D 6
5 E 3
6 F 5
(ID не обязательно идут с шагом 1)
То есть по этой таблице получается такое дерево:
.A -
.C +
...|-E +
.......|-B
.........|-F+
.............|-D
Вот теперь сам трабл.
У меня есть два списка с разными системами заполения. На данный момент меня интересует список, который заполняется таки образом
1 A
1 C
2 E
3 D
3 F
4 D
то есть цифрами устанавливается отступ.
вот еще один пример:
1
.2
..3
1
.2
..3
(для наглядности я сделал отступы)
Тут получится дерево с двумя корнями.
Я никак не могу придумать нормальную систему, по которой я данные из таблицы смог бы переформатироваться в вышепреведенную форму.
Дерево:
A
C+
-E+
--B
--F+
---D
Можно попробовать так: для каждого элемента идёшь к корню дерева, на каждом шаге(когда переходишь по
ссылке к родительскому узлу элемента) увеличиваешь на 1 счётчик шагов. При достижении корня дерева
счётчик шагов содержит значение отступа элемента от корня.
Пример для элемента с ID 6:
Читаешь для элемента 6 значение ParentID. Если оно нулевое(корень) - завершаем поиск., иначе инкремент счётчика шагов и переходим к
родительскому элементу по ParentID. Продолжаем в том же духе, пока не дойдём до корня. В результате счётчик шагов=отступ.
Или так : сразу же считать отступ при добавлении элемента в таблицу, т.е. хранить в таблице значения отступа от корня для каждого элемента - при добавлении нового элемента в поле Indent заносим значение поля Indent родительского элемента+1.
ID Name ParentID Indent
1 A 0 0
2 B 0 0
3 C 1 1
4 D 2 1
5 E 4 2
Дерево:
A
C+
-E+
--B
--F+
---D
Можно попробовать так: для каждого элемента идёшь к корню дерева, на каждом шаге(когда переходишь по
ссылке к родительскому узлу элемента) увеличиваешь на 1 счётчик шагов. При достижении корня дерева
счётчик шагов содержит значение отступа элемента от корня.
Пример для элемента с ID 6:
Читаешь для элемента 6 значение ParentID. Если оно нулевое(корень) - завершаем поиск., иначе инкремент счётчика шагов и переходим к
родительскому элементу по ParentID. Продолжаем в том же духе, пока не дойдём до корня. В результате счётчик шагов=отступ.
Или так : сразу же считать отступ при добавлении элемента в таблицу, т.е. хранить в таблице значения отступа от корня для каждого элемента - при добавлении нового элемента в поле Indent заносим значение поля Indent родительского элемента+1.
ID Name ParentID Indent
1 A 0 0
2 B 0 0
3 C 1 1
4 D 2 1
5 E 4 2
Я кстати в таблице и сохраняю позицию елемента в формате ID;ID;ID; и т.д.
Но этого мало, мне еще надо иметь правильную последовательность елементов, так как в таблице они могут находиться хаотично.
Тоесть из таблицы я получаю номера отступа в дереве, но не получаю правильную последовательно.
Я бы хотел каким-то образом получать из БД уже правильно отсортированый список.
Я бы хотел каким-то образом получать из БД уже правильно отсортированый список.
id, name, level ident
from
table1
connect by
parent_id = prior id
start with
parent_id = 0
order siblings by
id -- или name, если надо
Но это только для правильных БД.
Если вместо этого у таких вершин ParentID=-ID, тогда можно дать запрос
FROM table
ORDER BY ParentID, Ident, Name
тогда можно дать запрос
FROM table
ORDER BY ParentID, Ident, Name
Нельзя. Это работает только для одного уровня вложения. В SQL без встроенных возможностей получить сортировку по вложенным узлам нельзя математически. Если siblings не поддерживается, придется делать по одному запросу для каждого родителя с учетом вложенности. Больше владельцев - больше запросов.
Я никак не могу придумать нормальную систему, по которой я данные из таблицы смог бы переформатироваться в вышепреведенную форму.
Насколько я знаю, простыми средствами задача неразрешима в принципе.
Уже писал выше, что без поддержки со стороны сервера придется делать по одному запросу для каждого владельца рекурсивно. Это для получения твоих форм (если нужно именно оно).
Если нет - для отображения дерева из БД нужен класс, понимающий (транслирующий) реляционные отношения вложенности в дерево указателей.
Нельзя.<skipped>
Да, это так. Точнее не можно. Это же рекурсивная структура.
Меня запутало, что я деревья записываю в бинарный файл в порядке левостороннего обхода, и поэтому заполняю дерево линейно, проходя по записям этого файла учитывая только Ident.
id, name, level ident
from
table1
connect by
parent_id = prior id
start with
parent_id = 0
order siblings by
id -- или name, если надо
Но это только для правильных БД.
Под правильной БД подразумевается Oracle? ;)
Сразу не сказал, моя БД в аксесовском файле. Хотя есть и в MSSQL 2000 сервере.
Но я хотел бы чтобы програма работала с аксесовской базой, чтобы не заморачивать голову с SQL Server'ом.
Теперь по сути.
SQL Server does not support the Oracle START WITH…CONNECT BY clause. You can replace this in SQL Server by creating a stored procedure that performs the same task.
Но на аксесовской базе нельзя сделать процедурку.
На счет класса который понимает реляционные отношения вложености. То можно конечно такой написать. Но тогда прийдеться получать из БД все записи в этот клас, там их сортировать как надо, а потом передавать в класс деревовидного списка - неэфективно.
Под правильной БД подразумевается Oracle? ;)
Необязательно. Это часть стандарта SQL 92. Его стремится поддерживать Postgress и Cache', кажется.
Можно и функциональность order by siblings непосредственно в нем реализовать. Для полноты эмуляции. Не думаю, что в Oracle это сделано просто так.
Кстати, случай из практики: пока order by siblings не был реализован, в 8-й версии его было заменить нечем, сэмулировать его работу в SQL нельзя (опять-таки рекурсивный алгоритм).