Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 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.039 c
14-1078687570
Piter
2004-03-07 22:26
2004.04.11
Узнаем ли мы когда-нибудь правду?


4-1079608687
boa
2004-03-18 14:18
2004.04.11
Как программно узнать, что сервер НТ является терминал-сервером?


8-1069869678
Михайлов Антон
2003-11-26 21:01
2004.04.11
TV Capture Card


14-1082108227
.Lex
2004-04-16 13:37
2004.04.11
Соундтрек из "Бедной Насти"


1-1080227705
Bazil
2004-03-25 18:15
2004.04.11
Вопрос по QuickReport





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский