Форум: "Базы";
Текущий архив: 2009.04.19;
Скачать: [xml.tar.bz2];
ВнизПо умолчанию Рекурсивный запрос к БД - не могу сообразить как Найти похожие ветки
← →
frippy (2008-08-21 21:50) [0]есть список людей, с именами, адресами и т.д.
У каждой записи есть свой ID - генерится сервером (Interbase)
У некоторых людей в списке есть "подчинённые" - они получают свой ID, но ещё и номер "главного".
В итоге таблица получается "деревом" - у каждого подчинённого могут ещё быть люди в подчинении.
Когда выбираем "самого главного" - видим весь список людей.
Когда выбираем одного из подчинённых - видим список его подчинённых И подчинённых этого подчинённого.
Что не понимаю как сделать - вывести всех подчинённых выбранного подчинённого "вглубь"
Может я немонго сумбурно объяснил, наверное, но суть такова - выбрав на 1-м уровне я должен видеть все уровни вглубь (не важно сколько их),
выбрав 2-й уровень я должен увидеть всех на 3-м, 4-м и т.д. уровнях.
Посмотреть подчинённых без "рекурсии вглубь" - делается на ура и легко, а вот как дальше - не пойму.
Пишется всё на Delphi2006 + IB7
← →
stas © (2008-08-21 22:01) [1]Нужно объединить таблицу саму с собой столько раз сколько вложенностей, либо рекурсия либо цикл.
На работе пример есть на MSSQL, завтра скину.
Смысл такой объединяешь таблицу саму с сабой результат списываешь во временную таблицу, а потом в цикле объединяешь временную таблицу саму с собой и списываешь в нее же результат, пока результат небудет NULL.
← →
Евгений Р. (2008-08-21 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 © (2008-08-21 22:04) [3]тут посмотри:
http://delphimaster.net/view/3-1213899571/
← →
frippy (2008-08-21 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 (2008-08-21 22:14) [5]2stas - временная таблица не годится, у меня 10 человек будет добавлять записи и делать выборки одновременно
Евгений Р. - а можно поподробней, если не затруднит...?
← →
Евгений Р. (2008-08-21 22:40) [6]tbl - таблица с людьми
idf - идф. человека
idfGlavn-идф.начальника
Хранимая процедура
вх.параметр - Idf
выходной - IdfOut
результат - список idf всех подчиненных
внешний цикл - выбираем и выдаем всех подчиненных предыдущего уровня
внутренний цикл - рекурсивно выдаем для каждого подчиненного всех подчиненных
← →
frippy (2008-08-21 22:44) [7]идущий да обрящет....
думаю что удалось побороть, вот статья:
http://www.az-design.ru/Support/DataBase/Heiven13.shtml
конкретно - делаем процедуру и запрос
осталось проверить в деле......
← →
Prohodil Mimo © (2008-08-21 23:23) [8]ещё на ibase.ru есть статьи.
Но я предпочитаю на клиенте дерево генерить.
← →
stas © (2008-08-22 08:56) [9]frippy (21.08.08 22:06) [4]
Да хоть 100. Вы же придумали такую структуру - не я.
Тяжеловато конечно будет работать рекурсия. Я выше ссылку давал там я описывал как триггерами наполнять постоянную таблицу в момент заполнения вашей таблицы.
← →
место (2008-08-22 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 © (2008-08-22 15:11) [11]место (22.08.08 13:42) [10]
Нет это только 2-й уровень
← →
Труп Васи Доброго © (2008-08-22 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 © (2008-08-22 17:14) [13]http://yandex.ru/yandsearch?&text=%D1%81%D0%B2%D0%BE%D0%B8%D0%BC%D0%B8%20%D1%80%D1%83%D0%BA%D0%B0%D0%BC%D0%B8%20%D0%A4%D0%B8%D0%BB%D0%B8%D0%BF%D0%BF%D0%BE%D0%B2%D0%B0%20delphi&msp=1
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2009.04.19;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.059 c