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

Вниз

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

 
аппельсин   (2004-03-24 13:16) [0]

помогите написать запрос к таблице содержащей дерево.
необходимо организовать выборку всех ветвей с их потомками (и их потомками) начиная не от корня а с заданной ветви.


 
Digitman ©   (2004-03-24 13:32) [1]

за тебя запрос написать ? не зная структуры таблицы ?


 
Романов Р.В. ©   (2004-03-24 13:35) [2]

Я спросил у дерева... :)


 
Vlad ©   (2004-03-24 13:37) [3]


> аппельсин   (24.03.04 13:16)  

Насколько мне известно, иерархические запросы поддерживает только Oracle (возможно MS SQL, хотя не уверен), в остальных случаях нужна рекурсивная процедура.
P.S. Тип СУБД слабо указать ?


 
Романов Р.В. ©   (2004-03-24 13:39) [4]

Рекурсивно составляй запросы к потомкам и на основе этих данных составляй запрос по всем элементам


 
Курдль ©   (2004-03-24 13:42) [5]


> помогите написать запрос к таблице содержащей дерево

Если не на Оракле - то никогда не делайте этого!
Получите набор данных и в памяти его сортируйте, ровняйте, стройте, как хотите!


 
Digitman ©   (2004-03-24 13:53) [6]

есть и иной (достаточно простой) способ, который и безо всяких Ораклов позволит сформировать требуемый НД одним запросом, но при этом требуется вспомогательная таблица, хранящая инф-цию о дочерне-родительско-корневых связях узлов дерева

в этом случае в запросе будут участвовать обе таблицы


 
Анонимщик ©   (2004-03-24 13:58) [7]

См. http://ibase.ru/develop.htm
Там есть раздел
"Древовидные и иерархические структуры, хранение объектов"


 
VLAD-MAL   (2004-03-24 15:11) [8]

Вот тебе таблица, содержащая дерево:

/***               Generated by IBExpert 24.03.2004        ***/

SET SQL DIALECT 3;

SET NAMES WIN1251;

/***                                 Tables                                 ***/

CREATE GENERATOR PART_CATEGORY_ID_GEN;

CREATE TABLE PART_CATEGORY (
   PART_CATEGORY_ID       T_PART_CATEGORY_ID /* INTEGER */ NOT NULL,
   BASE_PART_CATEGORY_ID  T_BASE_PART_CATEGORY_ID /* INTEGER */ NOT NULL,
   FNAME_SHORT            T_FNAME_SHORT /* VARCHAR(84) */ NOT NULL,
   LOCATION               T_LOCATION /* INTEGER  */,
   CHILD_COUNT            T_CHILD_COUNT /* INTEGER 1 NOT NULL */
);

/***                              Primary Keys                              ***/

ALTER TABLE PART_CATEGORY ADD PRIMARY KEY (PART_CATEGORY_ID);

/***                                Indices                                 ***/

CREATE INDEX XIF154PART_CATEGORY ON PART_CATEGORY (BASE_PART_CATEGORY_ID);

/***                                Triggers                                ***/

SET TERM ^ ;

/* Trigger: PART_CATEGORY_GEN_ID */
CREATE TRIGGER PART_CATEGORY_GEN_ID FOR PART_CATEGORY
ACTIVE BEFORE INSERT POSITION 0
as
begin
   IF (new.Part_Category_id IS NULL) THEN
      new.Part_Category_id = GEN_ID(Part_Category_id_gen, 1);
end
^

/* Trigger: PART_CATEGORY_TREE_BIUD */
CREATE TRIGGER PART_CATEGORY_TREE_BIUD FOR PART_CATEGORY
ACTIVE BEFORE INSERT OR UPDATE OR DELETE POSITION 99
as
BEGIN   --  Категория товара - обеспечение фукционирования как дерева
 if (inserting or updating) then begin
   if (new.base_Part_Category_id is null) then
        new.base_Part_Category_id = 0;
   if (new.child_count is null) then
        new.child_count = 0;
   if (new.location is null)  then  -- Вполне достаточно для обеспечения последовательного размещения элементов
        new.location = GEN_ID(Part_Category_id_gen, 1); -- при перемещении между уровнями можно просто сбросить значение Location
 end

 if ((inserting) or
     (updating and
      (old.Base_Part_Category_ID <> new.Base_Part_Category_ID)
        )) then   -- Увеличить счетчик детей у нового родителя
         UPDATE Part_Category T SET T.CHILD_COUNT=T.CHILD_COUNT+1
           WHERE T.Part_Category_ID = new.Base_Part_Category_ID;

 if ((deleting) or
     (updating and
       (old.Base_Part_Category_ID <> new.Base_Part_Category_ID)
         )) then   -- Уменьшить счетчик детей у старого родителя
       UPDATE Part_Category T SET T.CHILD_COUNT=T.CHILD_COUNT-1
         WHERE T.Part_Category_ID = old.Base_Part_Category_ID;

 if (deleting) then -- Каскадное удаление. Если не требуется, то перекрывается на клиенте
     delete from Part_Category T
       where
         T.base_Part_Category_id = OLD.Part_Category_id;
END
^

/* Trigger: TD_PART_CATEGORY */
CREATE TRIGGER TD_PART_CATEGORY FOR PART_CATEGORY
ACTIVE AFTER DELETE POSITION 0
AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
   /* Part_Category описывает Part Запрет удаления родительской записи */
   select count(*)
     from Part
     where
       Part.part_category_id = OLD.part_category_id into numrows;
   IF (numrows > 0) THEN
   BEGIN
     EXCEPTION CUSTOM_RESTRICT "Удалять нельзя: имеются записи в связанной таблице "Прайс"";
   END

END
^

/* Trigger: TU_PART_CATEGORY */
CREATE TRIGGER TU_PART_CATEGORY FOR PART_CATEGORY
ACTIVE AFTER UPDATE POSITION 0
AS
DECLARE VARIABLE numrows INTEGER;
BEGIN
 /* Part_Category описывает Part Запрет изменения родительской записи */
 IF
   (OLD.part_category_id <> NEW.part_category_id) THEN
 BEGIN
   select count(*)
     from Part
     where
       Part.part_category_id = OLD.part_category_id into numrows;
   IF (numrows > 0) THEN
   BEGIN
     EXCEPTION CUSTOM_RESTRICT "Изменять нельзя: имеются записи в связанной таблице "Прайс"";
   END
 END

END
^

SET TERM ; ^

Вот тебе процедура, возвращающая то, что надо:

CREATE PROCEDURE GET_TREE_PART_CATEGORY (
   MASTER_PART_CATEGORY_ID INTEGER)
RETURNS (
   PART_CATEGORY_ID INTEGER,
   BASE_PART_CATEGORY_ID INTEGER,
   FNAME_SHORT VARCHAR(84),
   LOCATION INTEGER,
   CHILD_COUNT INTEGER)
AS
begin
 for select part_category_id, base_part_category_id, fname_short, location, child_count
 from Part_Category T
 where Base_Part_Category_id =:MASTER_Part_Category_id
 order by T.Location, T.FName_Short
 into :part_category_id, :base_part_category_id, :fname_short, :location, :child_count
  do begin
    suspend;
    if (Child_Count > 0) then
      for  select part_category_id, base_part_category_id, fname_short, location, child_count
      from get_tree_part_category(:Part_Category_id)
      into :part_category_id, :base_part_category_id, :fname_short, :location, :child_count
    do suspend;
  end
end

Вот тебе процедура для контроля достоверности (в пределах дерева) вводимых данных

CREATE PROCEDURE GET_PARENTS_PART_CATEGORY (
   ID INTEGER)
RETURNS (
   DID INTEGER,
   OID INTEGER)
AS
BEGIN
 WHILE (ID > 0) DO
   BEGIN
     SELECT t.Part_Category_id, t.base_Part_Category_id
     FROM Part_Category T
     WHERE T.Part_Category_id = :ID
     INTO :DID, :OID;
     ID=OID;
     SUSPEND;
   END
END

PS - все сгенерировано by ErWin 4.1 для FireBird 1.5



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

Текущий архив: 2004.04.11;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.042 c
1-1080052814
B-boy Dimo-N
2004-03-23 17:40
2004.04.11
конвертация txt -> doc


4-1079183758
name voe
2004-03-13 16:15
2004.04.11
Сроччно определить handle desktop


14-1081889693
Yanis
2004-04-14 00:54
2004.04.11
FTP


14-1079289669
Asteroid
2004-03-14 21:41
2004.04.11
Такое не бывает!


1-1079705992
V-Isa
2004-03-19 17:19
2004.04.11
Алгоритм определения количества "счастливых" чисел