Форум: "Базы";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];
ВнизРекурсивный запрос Найти похожие ветки
← →
YurikGl © (2004-03-13 12:18) [0]Уважаемые мастера.
Существует следующая задача - описать структуру объектов неограниченной вложненности друг в друга. Т.е. в моем случае объектом является сборка. Каждая сборка может в своем составе содержать другие сборки.
В структуре БД я описал это так
табл Сборки табл Связи
IdСборки IdСвязи
Название IdСборкиРодитель
....(параметры сборки) IdСборкиДочерний
Количество
...(параметры связи)
Далее необходимо выбрать все сборки содержащиеся в заданной на любом уровне.
В настоящее время решаю эту проблему так:
//описание классов
type
TSborkaRec = class
IdSborka:longint;
count:Longint;
constructor Create(S1:longint;S2:longint);
end;
TMyList = class (TList)
procedure MyAdd (S1:longint;S2:longint);
destructor Destroy; override;
end;
Constructor TSborkaRec.Create(S1:longint;S2:longint);
Begin
IdSborka:=S1;
count:=S2;
inherited Create;
End;
Procedure TMyList.MyAdd(S1:longint;S2:longint);
Var
Sb:TSborkaRec;
Begin
Sb:=TSborkaRec.Create(S1,S2);
Add(Sb);
End;
//сама процедура
Procedure TFormSborkaOtchet.Recur(IdSborka:longint);
var
List:TMyList;
s:string;
i:longint;
Rec:TSborkaRec;
Begin
List:=TMyList.Create;
ADODataSetvr.Active:=false;
s:="select [Связи].IdСборкиДочерний,[Связи].Количество From [Связи] where [Связи].IdСборкиРодитель="+IntToStr(IdSborka);
ADODataSetvr.CommandText:=s;
ADODataSetvr.Active:=true;
ADODataSetvr.First;
if ADODataSetvr.RecordCount>0 then
repeat
List.MyAdd(ADODataSetvr.Fields[0].Value,ADODataSetvr.Fields[1].Value);
ADOCommand1.CommandText:="insert into "+TableVrName+" ([IdСборки], [Количество]) values ("+IntToStr(ADODataSetvr.Fields[0].Value)+", "+IntToStr(ADODataSetvr.Fields[1].Value)+")";
ADOCommand1.Execute;
ADODataSetvr.Next;
Until ADOdatasetvr.EOF;
if List.Count>0 then
for i:=0 to List.Count-1 do begin
Rec:=TSborkaRec(List.items[i]);
recur(Rec.IdSborka);
end;
List.Free;
End;
// TableVrName - динамически создаваемая таблица, с полями IdСборки и Количество
По окончанию работы в ТableVrName получаем искомый набор.
Какие еще существуют способы решения поставленной задачи? Как можно оптимизировать представленный код?
← →
YurikGl © (2004-03-13 16:17) [1]Неужели все в FAQ описано?
← →
YurikGl © (2004-03-13 18:21) [2]Мнда... Надо было девушкой представиться. :)
← →
Romkin © (2004-03-13 18:28) [3]Ты думаешь, в воскресенье здесь просто куча народа сидит? Щаз!
Оххх... Ну написал - а как иначе-то? На Access нет процедур, а запросы рекурсию не допускают.
Структура таблиц, правда, у тебя не для дерева, а вообще сетевая, дерево в первом приближении делается так:
Сборка (ID, Название, Owner_ID references ID)
То есть третье поле - ID родителя, а у корня ID делается либо NULL, либо 0, как хочешь.
Остальное - http://www.ibase.ru/develop.htm
"Древовидные и иерархические структуры, хранение объектов"
Все касательно IB, но, думаю, разобраться можно :)
← →
YurikGl © (2004-03-13 19:05) [4]Структура сетевая. Это действительно так и должно быть т.к. БД реализует структуру изделий. И сборка типа "гайка" может и будет входить в большинство изделий. Вопрос был задан потому, что когда я создавал это, у меня не было опыта создания подобных структур и не было кого-нибудь, кто-бы мог посоветовать.
По указанной ссылке, я не нашел, по крайней мере с ходу, ничего про сетевые структуры.
В ближайшее время мне нужно будет перебросить все это на IB, а кроме как с Access я ни с чем серьезно не работал. Хотелось бы спросить, можно-ли с помощью хранимых процедур реализовать подобные вещи на IB. Как - сам разберусь (если можно конечно).
З.Ы. За это время здесь побывали и АП и Юрий Зотов и еще много кто. Так что народу может сидит и не куча, но, самые уважаемые мною, сидят. :)
← →
Nikolay M. © (2004-03-13 19:36) [5]Делать это хранимыми в IB, переносить всю логику на клиента (не самый оптимальный вариант) или вводить некоторую избыточность: у каждой связи дополнительно указывать, например, уровень, ID родителя-корня, последовательность ID-шек до родителя-корня. В первом случае нужно наличие ХП (в аксессе нет), в последнем - поддержка избыточности тригерами или хранимыми (опять же нет в аксессе). Так что либо делать все на клиенте + аксесс, либо сразу реализовывать на IB.
← →
YurikGl © (2004-03-13 19:40) [6]re [5] т.е. IB позволит реализовать рекурсивную функцию приведенную в [1]?
← →
Romkin © (2004-03-13 19:42) [7]urikGl © (13.03.04 19:05) [4]
Слушай, я уже показал, где взять деревья. Как насчет почитать? Думаешь, там о сборках ничего нет? Меня просто смутил IdСвязи, поэтому и сказал, что сетевая. НА самом деле - таки дерево :)) Точнее лес у тебя. Читай www.ibase.ru!
← →
Romkin © (2004-03-13 19:44) [8]YurikGl © (13.03.04 19:40) [6] Да, в IB возможны рекурсивные вызовы процедур. Правда, не знаю как в FB, но в IB5, если не ошибаюсь, глубина вызовов не более 255. Думаю, достаточно, сборка с 255 уровнями вложения - это что-то :)
← →
Nikolay M. © (2004-03-13 19:51) [9]
> Romkin © (13.03.04 19:44) [8]
> Да, в IB возможны рекурсивные вызовы процедур.
Думаешь, оно ему надо? Я лично рекурсию вообще злом считаю, а уж ХП рекурсивно вызывать - это вообще что-то с чем-то.
Тем более по ссылке в [3] вообще все шоколадом расписано, бери и пользуйся.
← →
YurikGl © (2004-03-13 20:00) [10]re [4]. Может я не понимаю разницу между древовидными и сетевыми структурами?
← →
Nikolay M. © (2004-03-13 20:06) [11]
> YurikGl © (13.03.04 20:00) [10]
Сетевая структура в общем случае - связанный граф. Любая вершина может быть связана с любой другой вершиной. Дерево - частный случай такой структуры.
http://algolist.manual.ru/
← →
YurikGl © (2004-03-13 20:09) [12]Ну дык, у меня родитель может иметь любое количество детей и дети любое количество родителей. Семантически исключаются только кольцевые ссылки.
в ссылке [3] нормально описаны только двуслойные сети - группы-пользователи, либо классические деревья, когда ребенок имеет одного родителя.
← →
YurikGl © (2004-03-13 20:11) [13]Добавлю, что каждая связь, помимо поля количество имеет поле позиция.
← →
Nikolay M. © (2004-03-13 20:32) [14]Так вопрос в итоге какой? Код работает? Похоже на правду, работает, вот и не трогай. Оптимизировать можно, как я уже сказал, если у каждой связи хранить не только ID родителя, а через запятую - всех родителей до корневого включительно. В этом случае не нужно делать несколько селектов, а достаточно одного ...WHERE [Связи].IdСборкиРодитель IN (:ParentIDs)
← →
YurikGl © (2004-03-13 20:43) [15]В общем я имел в виду, может существуют типовые решения поставленной задачи?
Продя по ссылкам, понял, что это, видимо, - не так.
Большое спасибо за ссылки и идею про оптимизацию.
← →
Romkin © (2004-03-13 23:41) [16]Охохо. НУ поторопился я! Деревья у тебя, просто их много. Есть сборка, в которую детали входят именно в виде дерева, все ж по блокам идет. А то, что разные наименования в разных сборках - так это уже детали.
← →
YurikGl © (2004-03-14 11:58) [17]re [16]
аппаратура
/ | \
/ | \
блок1 блок2 блок3
\ \ | | / /
\ \ | | / /
\ \| |/ /
\ | | /
| |\ /| /
| | Х | |
| |/ \| |
Элемент1 Элемент2
Есть сборка Аппаратура. Она состоит из сборок Блок1, Блок2 и Блок3. В состав кождого блока входят сборки Элемент1 и Элемент2, которые, в свою очередь, тоже из чего-то состоят.
На все эти сборки есть документация, цена, допустимые замены и еще куча параметров.
Где здесь дерево?
← →
Romkin © (2004-03-14 12:28) [18]Древний и интересный вопрос :)
Сборка: (Элемент | Сборка)...
Прими, что неразборная деталь - тожесамо, что и сборный блок.
Две таблицы:
Элементы (Элемент_ID, Наименование, ...)
Состав_Элемента (Элемент_ID, Подэлемент_ID, <кол-во>) - здесь как придется, либо количество (скорее всего достаточно), либо, как у тебя, уникальное поле, тогда кол-во подъэлементов = кол-во строк с подэлемент_ID у данного Элемент_ID (оба ссылаются на Элементы)
И что? Я утверждаю, что данная структура полностью обеспечивает данную схему. При этом Состав_Элемента - дерево!
А вот допустимые замены - увы, уже третья таблица. Скорее всего, группирующая взаимозаменяемые элементы?
Если выполняется правило, что если один элемент можно заменить на второй, то и второй можно заменить на первый:
в Элементы вводим CHANGE_GROUP_ID - идентификатор, у кого одинаковый - можно заменять (ну и таблицу наименований энтих самых CHANGE_GROUP_ID). Если нет - делаем таблицу аналогично состав_Элемента, первое поле - какой элемент заменяем, второе - на что можно заменить.
Вот и все. Но все строго деревянно :))
← →
Romkin © (2004-03-14 12:35) [19]Насчет[17] поясняю: перекрестные ребра на элементы - преобразуются в неперекрестные, указывающие на ссылку на элемент :)
Аппаратура
/ | \
/ | \
/ | \
/ | \
блок1 блок2 блок1
/ \ / \ ...
/ \ / \
/ \ / \
Элемент1 Элемент2 элемент1 элемент2
ID - та же ссылка :) Вот тебе и дерево :)))
← →
YurikGl © (2004-03-14 12:45) [20]Оно собственно так и реализовано
[1]
табл Сборки табл Связи
IdСборки IdСвязи
Название IdСборкиРодитель
....(параметры сборки) IdСборкиДочерний
Количество
...(параметры связи)
Состав одного элемента действительно дерево, но в ссылке [3] нормально описаны только двуслойные сети - группы-пользователи, либо классические деревья, когда ребенок имеет одного родителя т.е. структура типа (idСборка, IdРодительЭтойСборки, параметры...)
Нет ли где-описание структур подобных моей. Я думаю, что я - далеко не первый, кто столкнулся с подобной проблемой.
← →
Romkin © (2004-03-14 12:57) [21]Гыы... О чем я говорю: Связи твои - именно и описаны :)
Переставь поля, и все. То, что idСвязи нет - ну и что? Он не нужен!!! Связи (idСборкиДочерний, idРодитель) - с точностью до перестановки полей. Еще раз: У связи наименование есть? принимаем, что связь - это сборка, и пихаем все в одну таблицу :)
Разница между ними выделяется в дочерние к ней, а остается тип (если надо), указываюший, что это, сборка или элемент или ?связь?
Я вообще уверен, что понятие Связь вообще не надо.
Все так работают, я и сам это делал, все укладывается как родное. Есть блоки, состоящие из доугих блоков, состоящих из блоков... - строгая иерархия, при этом все уровни равноценны.
← →
Romkin © (2004-03-14 13:05) [22]Поясню:
ПУсть пимпа крепится болтом к плюкалке, которая двумя болтами привинчивается к дурынде, у которой еще загогулина есть :) Две дурынды вместе называются Хренотень.
Таблицы:
Элементы (elem_ID, название)
1. Болт
2. Пимпа
3. Плюкалка
4. Дурында
5. Загогулина
6. Хренотень
Соста_элемента (elem_ID, owner_ID, countNum)
1, 3, 1 // Болт крепит к плюкалке
1, 4, 2 // Два болта крепят к дурынде
2, 3, 1 // Пимпа крепится к плюкалке
3, 4, 1 // А плюкалка - к дурынде
5, 4, 1 // К дурынде еще загогулину надо
4, 6, 2 // Две дурынды - это хренотень
Уложил? :)))
← →
YurikGl © (2004-03-14 13:20) [23]Ну дык таблица Состав_Элемента аналогична таблице Связи.
в статье http://www.ibase.ru/devinfo/treedb2.htm повторюсь реализована двуслойная структура с выделением каждого слоя.
Единственная фраза про множественные связи
>>Разумеется, если-бы нам потребовалось хранить в базе данных генеалогическую информацию, то мы сделали-бы совершенно другую структуру БД. Просто завели-бы список "людей" и во второй таблице организовали между ними "родственные отношения".
По поводу IdСвязи, это поле осталось рудиментарным, на данный момент запись идентефицируется idРодитель, IdДочерний, Позиция.
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.038 c