Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2004.06.06;
Скачать: [xml.tar.bz2];

Вниз

Дерево в БД   Найти похожие ветки 

 
goozman   (2004-05-06 10:12) [0]

Помогите пожалуйста, есть таблица, главные поля (ID, PARENT_ID) по ним строится дерево- по полю ID я могу добратся к самому верхнему родителю, а теперь вопрос помогите создать запрос по которому можно по родителю (самому верхнему) узнать все дочерние его ветки! Очень надеюсь на Вашу помощь!


 
Соловьев ©   (2004-05-06 10:16) [1]


> самому верхнему родителю, а теперь вопрос помогите создать
> запрос по которому можно по родителю (самому верхнему) узнать
> все дочерние его ветки! Очень надеюсь на Вашу помощь!

www.ibase.ru


 
goozman   (2004-05-06 10:19) [2]

Наверное я неправильно выразился, мне надо не количество веток, а все записи с их ID


 
Соловьев ©   (2004-05-06 10:25) [3]


> goozman   (06.05.04 10:19) [2]

там все это есть


 
Курдль ©   (2004-05-06 11:06) [4]

Это не решается запросом (разве что на Оракле).


 
Соловьев ©   (2004-05-06 11:10) [5]


> Курдль ©   (06.05.04 11:06) [4]

ХП


 
Мунька   (2004-05-06 11:13) [6]

Одним запросом не решается. Я строила дерево из таблицы Access - дерево подразделений, находила также предков-потомков, но одним запросом это не решается, если интересно, могу кусок кода поиска потомков кинуть


 
Соловьев ©   (2004-05-06 11:15) [7]


> Мунька   (06.05.04 11:13) [6]

в Access - не решается в ИБ решается.


 
Курдль ©   (2004-05-06 11:16) [8]


> Соловьев ©

На ХП можно построить дерево с цепью, русалкой и ученым котом впридачу! Автор просил запрос. Но я считаю, что ради "дерева" не следует мучать сервер. Ведь все, что он сможет вернуть - последовательность деревянно-отсортированных записей! Преобразовывать их в стволы, ветки и узлы придется все равно на клиенте.


 
Мунька   (2004-05-06 11:19) [9]

>последовательность деревянно-отсортированных записей! >Преобразовывать их в стволы, ветки и узлы придется все равно на >клиенте.
Не вижу проблем такого преобразования


 
Соловьев ©   (2004-05-06 11:21) [10]


> Курдль ©   (06.05.04 11:16) [8]

а оракл вернет что? не
> последовательность деревянно-отсортированных записей!
?


 
Курдль ©   (2004-05-06 11:22) [11]


> Мунька   (06.05.04 11:19) [9]
> Не вижу проблем такого преобразования

Так я более того - не вижу проблем разложения древовидно-заточенного набора данных в дерево вовсе на клиенте! Это рекурсия в 10 строк!


 
Курдль ©   (2004-05-06 11:24) [12]


> Соловьев ©   (06.05.04 11:21) [10]
> а оракл вернет что? не
> > последовательность деревянно-отсортированных записей!

Ее самую, а где противоречия? Только оракл вернет по запросу, а не из ХП. Но я повторяю - чаще всего удобнее "делать дерево" на клиенте.


 
gu_est   (2004-05-06 11:26) [13]

>Курдль ©   (06.05.04 11:16) [8]
Что значит не мучать сервер? А кого мучать? Клиента?
Загнать на клиента ВСЕ и там строить дерево? А на кой тогда сервер вообще нужен?


 
Соловьев ©   (2004-05-06 11:28) [14]


> Только оракл вернет по запросу, а не из ХП

Просто разработчики Оракла уже это реализовали. Вот тебе и запрос. Но не вижу сложности в ХП...
не будем спорить, автор и сам решит что ему нужно...
Противоречие здесь.

> Преобразовывать их в стволы, ветки и узлы придется все равно
> на клиенте.

Таким образом я понял что Оракл вернет уже типа готовой компоненты... Значит я не понял ответа.
Но имхо ХП самое оно.


 
Sergey_Masloff   (2004-05-06 11:28) [15]

Курдль ©   (06.05.04 11:24) [12]
В запросе надо отобрать все счета клиента а клиент это иерархическая структура - центральный офис, представительства и так далее. Куда ты в этой задаче засунешь свое дерево на клиенте?
Это только самый простой пример реально деревью могут использоваться на сервере и покруче.


 
Курдль ©   (2004-05-06 11:29) [16]


> gu_est   (06.05.04 11:26) [13]
> Загнать на клиента ВСЕ и там строить дерево? А на кой тогда
> сервер вообще нужен?

Именно загнать на клиента ВСЕ! Ведь от перестроения записей их количество не изменится! А сервер БД нужен вовсе не для того, чтобы заниматься бантиками клиентского интерфейса.


 
Курдль ©   (2004-05-06 11:34) [17]


> Соловьев ©   (06.05.04 11:28) [14]

> Таким образом я понял что Оракл вернет уже типа готовой
> компоненты... Значит я не понял ответа.
> Но имхо ХП самое оно.

Нифига похожего оно не вернет! Только root-node-subnode...node-subnode-subsubnode... и т.д. Еще поле LEVEL.
Компонент визуальный наполнять все равно придется со стороны клиента - иначе никак!


 
Соловьев ©   (2004-05-06 11:34) [18]


> Ведь от перестроения записей их количество не изменится!
>

это если один клиент :)
А если много? У меня ветка строится когда пользователь решил ее рскрыть. И сразу выполняется запрос к БД. А в твоем варианте данные не актуальны.


 
Johnmen ©   (2004-05-06 11:36) [19]

>Именно загнать на клиента ВСЕ!

Да ? А если их много ? А нас много не интересует ?

>Ведь от перестроения записей их количество не изменится!

А где здесь "перестроение" ?


 
Курдль ©   (2004-05-06 11:37) [20]


> У меня ветка строится когда пользователь решил ее рскрыть.

Это разумно. Не спорю. Но я, чаще всего, беру TdxDBTreeList, подставляю ему набор данных и не парюсь :)


 
gu_est   (2004-05-06 11:43) [21]

Автор вообще не заострял внимание на визуализации дерева как такового (может полученный в результате запроса набор данных он собарается использовать для дальнейших вычислений, а не для визуализации в виде дерева).
Посему ХП (ИМХО) это то, что "доктор прописал"


 
Мунька   (2004-05-06 11:46) [22]

Ладно, ловите. Суть такая. Таблица, как я понимаю, как у нашего вопрошающего. Сначала я извлекаю данные все, а уж потом строю дерево, результат, то бишь дерево, скидываю в StringList

//---------------------------------------------------------------
//Извлечение всех записей и скидывание их в StringList при помощи рекурсивной функции RecursDepartment, для идентификаторов используется отдельный TStringList * DepListId
bool TDM::SelectAllDepartment(WideString ConnectionADO, TStringList * DepList, TStringList * DepListId)
{
int RecNo;

if(ADOQDepart->Active)
 ADOQDepart->Close();
  ADOConnection1->Connected  = false;
  ADOConnection1->ConnectionString = ConnectionADO;
  ADOConnection1->Connected  = true;
  ADOQDepart->Connection = ADOConnection1;

ADOQDepart->SQL->Clear();
ADOQDepart->SQL->Add("SELECT * FROM  tdivision ORDER BY id_parent, id_division");
try{
  ADOQDepart->Open();
}
catch(...)
{
 return false;
}
ADOQDepart->First();
DepList->Clear();

if(DepListId!=NULL)
DepListId->Clear();
while(!ADOQDepart->Eof&&(ADOQDepart->FieldByName("id_parent")->AsInteger==-1 ) )
{
  DepList->Add(ADOQDepart->FieldByName("name_division")->AsString);
    if(DepListId!=NULL)
      DepListId->Add(IntToStr(ADOQDepart->FieldByName("id_division")->AsInteger));

  RecNo =ADOQDepart->RecNo;
  RecursDepartment(DepList, ADOQDepart->FieldByName("id_division")->AsInteger, DepListId);
  ADOQDepart->RecNo=RecNo;
  ADOQDepart->Next();
}

return true;
}
//сама рекурсивная функция
void TDM::RecursDepartment(TStringList * DepList, int id_parent, TStringList * DepListId)
{
int RecNo;

 while(!ADOQDepart->Eof)
 {
  if(ADOQDepart->FieldByName("id_parent")->AsInteger==id_parent)
   {
    DepList->Add(ADOQDepart->FieldByName("name_division")->AsString);
    if(DepListId!=NULL)
      DepListId->Add(IntToStr(ADOQDepart->FieldByName("id_division")->AsInteger));
    RecNo = ADOQDepart->RecNo;
    RecursDepartment(DepList, ADOQDepart->FieldByName("id_division")->AsInteger, DepListId);
    ADOQDepart->RecNo=RecNo;

   }
   ADOQDepart->Next();
 }

}


 
Мунька   (2004-05-06 11:47) [23]

// и кусок кода, для вызова всего этого хозяйства, одна функция выводит в грид SetStringListToGrig, вторая - в дерево
DM->SelectAllDepartmentToTree
...........................................
DeparmentList = new TStringList();
DeparmentListId = new TStringList();
DM->SelectAllDepartment(ConnectionADO, DeparmentList, DeparmentListId);
  ClearGrid(SGDivision, MIN_ROWCOUNT_DEPARTMENT);
 SetStringListToGrig(SGDivision, DeparmentList, MIN_ROWCOUNT_DEPARTMENT, 0);
 SGDivisionSelectCell(Sender,  0, 1,CanSelect);
 DM->SelectAllDepartmentToTree(ConnectionADO, TreeViewDep);
.......... дальше по коду...........................
//----------------------SetStringListToGrig вывод извлеченного дерева в грид------
void SetStringListToGrig(TStringGrid *sg, TStringList *sl, int min_rowcount, int col_num)
{
int i;
for(i=0; i< sl->Count; i++)
{
  if(i==(sg->RowCount-sg->FixedRows ))
      sg->RowCount +=min_rowcount;
  sg->Cells[col_num][i+sg->FixedRows] = sl->Strings[i];

}

}


 
Мунька   (2004-05-06 11:48) [24]

//Вывод в дерево
bool TDM::SelectAllDepartmentToTree(WideString ConnectionADO, TTreeView *TreeViewDep)
{
int RecNo;

if(ADOQDepart->Active)
 ADOQDepart->Close();

 ADOQDepart->ConnectionString = ConnectionADO;
ADOQDepart->SQL->Clear();
ADOQDepart->SQL->Add("SELECT * FROM  tdivision ORDER BY id_parent, id_division");
try{
  ADOQDepart->Open();
}
catch(...)
{
 return false;
}
ADOQDepart->First();
TreeViewDep->Items->Clear();
while(!ADOQDepart->Eof&&(ADOQDepart->FieldByName("id_parent")->AsInteger==-1 ) )
{
 // DepList->Add(ADOQDepart->FieldByName("name_division")->AsString);
  TreeViewDep->Items->Add(NULL, ADOQDepart->FieldByName("name_division")->AsString);

  RecNo =ADOQDepart->RecNo;
 // RecursDepartmentList(DepList, ADOQDepart->FieldByName("id_division")->AsInteger, DepListId);
  RecursDepartmentList(TreeViewDep, ADOQDepart->FieldByName("id_division")->AsInteger, TreeViewDep->Items->Item[TreeViewDep->Items->Count-1]);
  ADOQDepart->RecNo=RecNo;
  ADOQDepart->Next();
}
// ADOQDepart->

return true;
}
//рекурсия построения дерева
void TDM::RecursDepartmentList(TTreeView *TreeViewDep, int id_parent, TTreeNode *NodeParent)
{
int RecNo;

 while(!ADOQDepart->Eof)
 {
  if(ADOQDepart->FieldByName("id_parent")->AsInteger==id_parent)
   {
    TreeViewDep->Items->AddChild(NodeParent, ADOQDepart->FieldByName("name_division")->AsString);
    RecNo = ADOQDepart->RecNo;
    RecursDepartmentList(TreeViewDep, ADOQDepart->FieldByName("id_division")->AsInteger, TreeViewDep->Items->Item[TreeViewDep->Items->Count-1]);
    ADOQDepart->RecNo=RecNo;

   }
   ADOQDepart->Next();
 }

}


 
Мунька   (2004-05-06 11:48) [25]

//И напоследок, есть предок, извлечь всех его потомков
bool TDM::SelectLastLevel(WideString ConnectionADO, int id_parent)
{
TStringList *Id= new TStringList(), *list_parent = new TStringList()  ;
int  i;    // * list_id = new [1], size_list_id = 1,
AnsiString InString;
 if(ADOQLastLevel->Active)
 ADOQLastLevel->Close();

 ADOQLastLevel->ConnectionString = ConnectionADO;
 list_parent->Add(IntToStr(id_parent));
 do{
     ADOQLastLevel->SQL->Clear();
    ADOQLastLevel->SQL->Add("SELECT id_division, id_parent FROM  tdivision WHERE id_parent IN(");
          InString = "";
    for(i=0; i<list_parent->Count; i++)
    {
     if ( ((i+1)%100)==0)
     {
       ADOQLastLevel->SQL->Add(InString);
       InString = "";
     }
     InString += list_parent->Strings[i];
     if(i<(list_parent->Count-1) )
      InString +=", ";
     else InString +=")";
    }
     ADOQLastLevel->SQL->Add(InString);
    ADOQLastLevel->SQL->Add("ORDER BY id_parent, id_division");
     try{
        if(!ADOQLastLevel->Prepared)
         ADOQLastLevel->Prepared = true;

        ADOQLastLevel->Open();
        }
     catch(...)
    {
        delete Id;
        delete list_parent;
       return false;
    }

      for(i=0; i<list_parent->Count; i++)
      {
        ADOQLastLevel->Filtered = false;
        ADOQLastLevel->Filter = "id_parent = "+ list_parent->Strings[i];
        try{
        ADOQLastLevel->Filtered = true;
        }
        catch(...)
        {
         continue;
        }
           if(ADOQLastLevel->RecordCount==0)
         Id->Add(list_parent->Strings[i]);

      }//end for

          list_parent->Clear();
      ADOQLastLevel->Filtered = false;
      ADOQLastLevel->First();
      while(!ADOQLastLevel->Eof)
      {
       list_parent->Add(ADOQLastLevel->FieldByName("id_division")->AsString);
       ADOQLastLevel->Next();
      }

    }
 while(ADOQLastLevel->RecordCount>0);
   
   ADOQLastLevel->SQL->Clear();
   ADOQLastLevel->SQL->Add("delete from tdivision_tmp");
    try{
         if(!ADOQLastLevel->Prepared)
         ADOQLastLevel->Prepared = true;

        ADOQLastLevel->ExecSQL();

      }
  catch(...)
  {
    delete Id;
   delete list_parent;
   return false;
  }

        ADOQLastLevel->SQL->Clear();
    ADOQLastLevel->SQL->Add("INSERT INTO tdivision_tmp ");
    ADOQLastLevel->SQL->Add("SELECT * FROM  tdivision WHERE id_division IN(");
   
        InString = "";
    for(i=0; i<Id->Count; i++)
    {
     if ( ((i+1)%100)==0)
     {
       ADOQLastLevel->SQL->Add(InString);
       InString = "";
     }
     InString += Id->Strings[i];
     if(i<(Id->Count-1) )
      InString +=", ";
     else InString +=")";
    }
       ADOQLastLevel->SQL->Add(InString);

     try{
         if(!ADOQLastLevel->Prepared)
         ADOQLastLevel->Prepared = true;

        ADOQLastLevel->ExecSQL();

      }
  catch(...)
  {
   delete Id;
   delete list_parent;
   return false;
  }

   delete Id;
   delete list_parent;
   return true;
}



 
Соловьев ©   (2004-05-06 11:49) [26]


> DepListId->Add(IntToStr(ADOQDepart->FieldByName("id_division")->AsInteger));

слабенько :) А как насчет AddObject? ИМХО возможностей больше. И для ИБ есть уже готовые с исходниками. Брать на www.fibplus.com.ua в старье


 
Мунька   (2004-05-06 11:55) [27]

>>слабенько :) А как насчет AddObject?
Никак. Не помню из каких соображений, но вариант с добавлением объекта был отброшен. Наверное, из-за того, что объект должен быть наследником TObject, все-таки, а не просто целым числом.


 
Курдль ©   (2004-05-06 11:55) [28]


> Мунька

Это все об одном дереве????????!!!!!!!   8-()
Я же сказал 10 строк, а не 510!


 
Соловьев ©   (2004-05-06 11:59) [29]


> Это все об одном дереве????????!!!!!!!   8-()
> Я же сказал 10 строк, а не 510!

конечно когда за тебя все сделали

> Но я, чаще всего, беру TdxDBTreeList, подставляю ему набор
> данных и не парюсь :)



> Мунька   (06.05.04 11:55) [27]
> >>слабенько :) А как насчет AddObject?
> Никак. Не помню из каких соображений, но вариант с добавлением
> объекта был отброшен. Наверное, из-за того, что объект должен
> быть наследником TObject, все-таки, а не просто целым числом.

При использовании AddObject можно в узле хранить ссылку на структуру где хранить об узле кучи инфы, котора облегчает построение.


 
Мунька   (2004-05-06 11:59) [30]

>Это все об одном дереве????????!!!!!!!   8-()
>Я же сказал 10 строк, а не 510!
Там разные варианты - вывод в грид, в дерево, поиск потомков.. то есть это еще и визуальная обработка


 
Мунька   (2004-05-06 12:01) [31]

>При использовании AddObject можно в узле хранить ссылку на >структуру где хранить об узле кучи инфы, котора облегчает >построение.
Можно, но в данной программе хрен редьки не слаще


 
Курдль ©   (2004-05-06 12:03) [32]


> Мунька   (06.05.04 11:48) [24]

ЗАЧЕМ ВЫ ЭТО ВЫЛОЖИЛИ???
Неужели чтобы "передать опыт"? То, что Вы понаписали внутри ХП - чудовищно! Какие-то временные таблицы, бесчисленные селекты...
Что Вы хотели показать?


 
Соловьев ©   (2004-05-06 12:06) [33]


>  То, что Вы понаписали внутри ХП - чудовищно!

это как раз клиент :)


 
Курдль ©   (2004-05-06 12:08) [34]

Вот клиент:

//------------------------------------------------------------------------------
procedure TfrmAccounts.SortAccList(aList: TList);
var y, iy: Integer; py: ptrAcc;
 procedure BuildLink(var ptr: ptrAcc; var Index: Integer);
 var x: Integer; px: ptrAcc;
 begin
  inc(Index);
  for x:=0 to aList.Count-1 do
   begin
    px:=aList.Items[x];
    if (px.pr = ptr.id) and (px.index = 0) then
     begin
      px.index:=Index;
      px.level:=ptr.level+1;
      BuildLink(px, Index);
      ptr.dt0:=ptr.dt0+px.dt0;
      ptr.kt0:=ptr.kt0+px.kt0;
     end;
   end;
 end;
begin
 if aList = nil then Exit;
 iy:=1;
 for y:=0 to aList.Count-1 do
  begin
   py:=aList.Items[y];
   if py.pr = 0 then
    begin
     py.index:=iy;
     BuildLink(py,iy);
    end;
  end;
 aList.Sort(SortCompareIndex);
end;
//------------------------------------------------------------------------------



 
Соловьев ©   (2004-05-06 12:08) [35]


> Можно, но в данной программе хрен редьки не слаще

ну-ну... советую взглянуть на исходники готовых DBTreeView


 
Johnmen ©   (2004-05-06 12:09) [36]

>Курдль ©   (06.05.04 12:03) [32]
>Что Вы хотели показать?

А то ты не понял ? :)
Показать, что CB круче D, и эту крутизну успешно штурмовал тов. Мунька
Кстати, что-то текста маловато он привел... Требую продолжения банкета !


 
Соловьев ©   (2004-05-06 12:11) [37]


> aList.Sort(SortCompareIndex);

странно...
aList.Sort(@SortCompareIndex);?
и вообще не понятно к чему твой код :)


 
}|{yk ©   (2004-05-06 12:14) [38]

http://delphimaster.net/view/3-1083829796/


 
Мунька   (2004-05-06 12:18) [39]

>Неужели чтобы "передать опыт"? То, что Вы понаписали внутри ХП -> чудовищно! Какие-то временные таблицы, бесчисленные селекты...
>Что Вы хотели показать?
Всего-навсего ответила на вопрос, где при построении дерева не использовалась НИКАКАЯ специфика СУБД, все в рамках Ansi - стандарта. Если за вас УЖЕ извлечены все потомки - это хорошо, здесь показано все с 0 (почти, как format c:).

Не считаю CB круче Делфи, просто пишу на нем, мне удобнее.
И еще не штурмовал, а штурмовалА


 
Курдль ©   (2004-05-06 12:18) [40]


> aList.Sort(@SortCompareIndex);

Не обязательно - можно и без @.


> и вообще не понятно к чему твой код :)

Да "не вынесла душа поэта" :))) Привел код, который выстраивает данные в древовидную структуру и еще суммирует остатки по счетам "вверх по иерархии". Это не 10 строк, а аж 30...



Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2004.06.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.64 MB
Время: 0.041 c
3-1084772982
ss300
2004-05-17 09:49
2004.06.06
Странная Ошибка при вызове метода Post;


1-1085455823
пинг
2004-05-25 07:30
2004.06.06
Сжатие изображений при помощи нейронных сетей


14-1085248282
NetBreaker666
2004-05-22 21:51
2004.06.06
Привет, НАРОД! Я вернулся! Было ли здесь че-нить интересное


1-1085636689
andruxa
2004-05-27 09:44
2004.06.06
3 вопроса от незнания. Элемент Static. Tpanel. Компилятор дельфи.


6-1082466371
alan2
2004-04-20 17:06
2004.06.06
Пересылка файла через Сокеты от клиента к серверу





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский