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

Вниз

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

 
аппельсин   (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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.038 c
1-1079627370
Gero
2004-03-18 19:29
2004.04.11
Неперекрывающееся окно


7-1079959110
Kalishenko Stas
2004-03-22 15:38
2004.04.11
Владелец файла в Novell


14-1078885744
X9
2004-03-10 05:29
2004.04.11
Про возраст


1-1079952463
Dimbas
2004-03-22 13:47
2004.04.11
TWebBrowser и cursor


7-1075808615
Dran
2004-02-03 14:43
2004.04.11
Отжатие клавиши Win





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