Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.04.11;
Скачать: CL | DM;

Вниз

Рекурсивный запрос   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.031 c
9-1064932419
ZLODey
2003-09-30 18:33
2004.04.11
DelphiX, где ИСКАТЬ?


7-1075205447
Карелин Артем
2004-01-27 15:10
2004.04.11
Напомните пожалуйста АТ команду на снятие трубки модемом


1-1080130326
Th
2004-03-24 15:12
2004.04.11
Библиотека строковых функций


1-1079926032
Sphinx
2004-03-22 06:27
2004.04.11
TImageList


7-1076066126
$tranger
2004-02-06 14:15
2004.04.11
Проблема с пакетом "MySysInfo"