Конференция "Базы" » По умолчанию Рекурсивный запрос к БД - не могу сообразить как [Ib7]
 
  • frippy (21.08.08 21:50) [0]
    есть список людей, с именами, адресами и т.д.
    У каждой записи есть свой ID - генерится сервером (Interbase)
    У некоторых людей в списке есть "подчинённые" - они получают свой ID, но ещё и номер "главного".
    В итоге таблица получается "деревом" - у каждого подчинённого могут ещё быть люди в подчинении.
    Когда выбираем "самого главного" - видим весь список людей.
    Когда выбираем одного из подчинённых - видим список его подчинённых И подчинённых этого подчинённого.
    Что не понимаю как сделать - вывести всех подчинённых выбранного подчинённого "вглубь"
    Может я немонго сумбурно объяснил, наверное, но суть такова - выбрав на 1-м уровне я должен видеть все уровни вглубь (не важно сколько их),
    выбрав 2-й уровень я должен увидеть всех на 3-м, 4-м и т.д. уровнях.
    Посмотреть подчинённых без "рекурсии вглубь" - делается на ура и легко, а вот как дальше - не пойму.
    Пишется всё на Delphi2006 + IB7
  • stas © (21.08.08 22:01) [1]
    Нужно объединить таблицу саму с собой столько раз сколько вложенностей, либо рекурсия либо цикл.
    На работе пример есть на MSSQL, завтра скину.
    Смысл такой объединяешь таблицу саму с сабой результат списываешь во временную таблицу, а потом в цикле объединяешь временную таблицу саму с собой и списываешь в нее же результат,  пока результат небудет NULL.
  • Евгений Р. (21.08.08 22:04) [2]
    for
      select idf
      from tbl
      where idfGlavn=:idf into :idfOut do Begin
      suspend;
      for select idf
           from ЭтаПроцедура(:idfOut) into :idfOut do suspend;
    End;
  • stas © (21.08.08 22:04) [3]
  • frippy (21.08.08 22:06) [4]
    Объединять саму с собой таблицу это хорошо, но...у меня 10 машин будут одновременно делать это. Думаю варинат не приемлем :(

    А вот рекурсия-цикл - да, но не могу сообразить как
    Для одного человека я сделал так:

    var
     number: integer;
    begin
     if DBGrid4.SelectedField.AsString<>'' then
    //если есть человек, чьих подчинённых ищем
       begin
         IBQuery3.SQL.Clear;
         IBQuery3.SQL.Add('select * from list where num='+DBGrid4.SelectedField.AsString);
    //нашли человека, узнаём кто его "главный"
         IBQuery3.Open;
         number:=DBGrid4.SelectedField.AsInteger;
         IBQuery3.Locate('num',number,[]);
         IBQuery1.SQL.Clear;
         IBQuery1.SQL.Add('select * from list where main='''+Inttostr (number)+'''');
    //нашли всех, у кого главным записан человек с ID=number
         IBQuery1.Open;
     end;

    это работает на любую "глубину" но только для одного человека и только его подчинённых.
  • frippy (21.08.08 22:14) [5]
    2stas - временная таблица не годится, у меня 10 человек будет добавлять записи и делать выборки одновременно

    Евгений Р. - а можно поподробней, если не затруднит...?
  • Евгений Р. (21.08.08 22:40) [6]
    tbl - таблица с людьми
    idf - идф. человека
    idfGlavn-идф.начальника

    Хранимая процедура
    вх.параметр - Idf
    выходной - IdfOut

    результат - список idf всех подчиненных

    внешний цикл - выбираем и выдаем всех подчиненных предыдущего уровня
    внутренний цикл - рекурсивно выдаем для каждого подчиненного всех подчиненных
  • frippy (21.08.08 22:44) [7]
    идущий да обрящет....

    думаю что удалось побороть, вот статья:
    http://www.az-design.ru/Support/DataBase/Heiven13.shtml

    конкретно - делаем процедуру и запрос

    осталось проверить в деле......
  • Prohodil Mimo © (21.08.08 23:23) [8]
    ещё на ibase.ru есть статьи.
    Но я предпочитаю на клиенте дерево генерить.
  • stas © (22.08.08 08:56) [9]
    frippy   (21.08.08 22:06) [4]
    Да хоть 100. Вы же придумали такую структуру - не я.
    Тяжеловато конечно будет работать рекурсия. Я выше ссылку давал там я описывал как триггерами наполнять постоянную таблицу в момент заполнения вашей таблицы.
  • место (22.08.08 13:42) [10]
    нет возможности проверить, но по идее так можно получить полный список

    select a.id_people, a.people_name, b.id_people, b.people_name
    from t_people a, t_people b
    where a.id_people = b.id_owner
    order by a.id_people, b.id_people
  • stas © (22.08.08 15:11) [11]
    место   (22.08.08 13:42) [10]
    Нет это только 2-й уровень
  • Труп Васи Доброго © (22.08.08 16:44) [12]
    вот тебе процедура готовая и работающая

    SET TERM ^ ;

    CREATE OR ALTER PROCEDURE ADRESS_SEL_DOWN (
       id1 INTEGER)
    RETURNS (
       id INTEGER)
    AS
    begin
     for SELECT id FROM s_adres where s_adres.pid=:id1 into :id DO
       begin
         suspend;
         IF (EXISTS(SELECT id FROM s_adres where s_adres.pid =:id)) THEN
           BEGIN
             FOR SELECT id from ADRESS_SEL_DOWN(:id) INTO :id DO
               SUSPEND;
           END
       end

    end^

    SET TERM ; ^

    таблица s_adres в ней ID это ID, а PID это Parent ID короче всё как у тебя.
  • Vlad Oshin © (22.08.08 17:14) [13]
 
Конференция "Базы" » По умолчанию Рекурсивный запрос к БД - не могу сообразить как [Ib7]
Есть новые Нет новых   [134473   +28][b:0][p:0.001]