Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Как заполнить дерево?

292
21 февраля 2006 года
Matush
726 / / 14.01.2004
У меня есть деревовидный список, который надо заполнить данными из БД.

В БД данные храню в такой форме:

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
(для наглядности я сделал отступы)
Тут получится дерево с двумя корнями.

Я никак не могу придумать нормальную систему, по которой я данные из таблицы смог бы переформатироваться в вышепреведенную форму.
1.8K
21 февраля 2006 года
k3Eahn
365 / / 19.12.2005
Цитата:
Originally posted by Matush
У меня есть деревовидный список, который надо заполнить данными из БД.

В БД данные храню в такой форме:

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

292
21 февраля 2006 года
Matush
726 / / 14.01.2004
Цитата:
Originally posted by k3Eahn
Дерево:
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; и т.д.
Но этого мало, мне еще надо иметь правильную последовательность елементов, так как в таблице они могут находиться хаотично.
Тоесть из таблицы я получаю номера отступа в дереве, но не получаю правильную последовательно.
Я бы хотел каким-то образом получать из БД уже правильно отсортированый список.

10
21 февраля 2006 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by Matush
Я бы хотел каким-то образом получать из БД уже правильно отсортированый список.


 
Код:
select
  id, name, level ident
from
  table1
connect by
  parent_id = prior id
start with
  parent_id = 0
order siblings by
  id -- или name, если надо

Но это только для правильных БД.
7.9K
21 февраля 2006 года
uki_
122 / / 26.01.2006
Обычно, у вершин, которые не имеют родителя ParentID = 0.
Если вместо этого у таких вершин ParentID=-ID, тогда можно дать запрос
 
Код:
SELECT ID, Name, ParentID, Ident
  FROM table
  ORDER BY ParentID, Ident, Name
10
21 февраля 2006 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by uki_
тогда можно дать запрос
 
Код:
SELECT ID, Name, ParentID, Ident
  FROM table
  ORDER BY ParentID, Ident, Name


Нельзя. Это работает только для одного уровня вложения. В SQL без встроенных возможностей получить сортировку по вложенным узлам нельзя математически. Если siblings не поддерживается, придется делать по одному запросу для каждого родителя с учетом вложенности. Больше владельцев - больше запросов.

10
21 февраля 2006 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by Matush
Я никак не могу придумать нормальную систему, по которой я данные из таблицы смог бы переформатироваться в вышепреведенную форму.


Насколько я знаю, простыми средствами задача неразрешима в принципе.

Уже писал выше, что без поддержки со стороны сервера придется делать по одному запросу для каждого владельца рекурсивно. Это для получения твоих форм (если нужно именно оно).

Если нет - для отображения дерева из БД нужен класс, понимающий (транслирующий) реляционные отношения вложенности в дерево указателей.

7.9K
21 февраля 2006 года
uki_
122 / / 26.01.2006
Цитата:
Originally posted by Freeman
Нельзя.<skipped>

Да, это так. Точнее не можно. Это же рекурсивная структура.
Меня запутало, что я деревья записываю в бинарный файл в порядке левостороннего обхода, и поэтому заполняю дерево линейно, проходя по записям этого файла учитывая только Ident.

292
22 февраля 2006 года
Matush
726 / / 14.01.2004
Цитата:
Originally posted by Freeman
 
Код:
select
  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.
Но на аксесовской базе нельзя сделать процедурку.

На счет класса который понимает реляционные отношения вложености. То можно конечно такой написать. Но тогда прийдеться получать из БД все записи в этот клас, там их сортировать как надо, а потом передавать в класс деревовидного списка - неэфективно.

10
22 февраля 2006 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by Matush
Под правильной БД подразумевается Oracle? ;)


Необязательно. Это часть стандарта SQL 92. Его стремится поддерживать Postgress и Cache', кажется.

Цитата:
Но тогда прийдеться получать из БД все записи в этот клас, там их сортировать как надо, а потом передавать в класс деревовидного списка - неэфективно.


Можно и функциональность order by siblings непосредственно в нем реализовать. Для полноты эмуляции. Не думаю, что в Oracle это сделано просто так.

Кстати, случай из практики: пока order by siblings не был реализован, в 8-й версии его было заменить нечем, сэмулировать его работу в SQL нельзя (опять-таки рекурсивный алгоритм).

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог