Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Выборка всех потомков узла MySQL  (Прочитано 8110 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Rifler
Новенький

ru
Offline Offline

« : 01-05-2011 13:36 » 

Всем добрый день.
В данной статье - https://club.shelek.ru/viewart.php?id=307#post_classic - рассматривалась хранимая процедура, которая по id записи выбирает всех ее предков.
Приведу код ХП, чтобы лишний раз не переходить

Код:
CREATE PROCEDURE fetch_parent_ids(
    IN name_table VARCHAR(64),
    IN name_id VARCHAR(64),
    IN name_parent VARCHAR(64),
    IN base INT UNSIGNED,
    IN max_levels INT,
    IN result_in_var BOOLEAN,
    OUT result_ids MEDIUMTEXT
)
BEGIN
    DECLARE currlevel INT;
    DECLARE ids MEDIUMTEXT DEFAULT '';

    IF result_in_var THEN
        SET result_ids = '';
    END IF;

    SET @parent = base;

    -- В случае если max_levels равно 0, то допускаем 100000 уровней.
    -- Отрицательные значения дадут один уровень — это побочное явление.
    SET currlevel = IF(max_levels, 1, -100000);

    SET @stm = CONCAT(
        'SELECT ', name_parent, ' INTO @parent FROM ', name_table, ' WHERE ', name_id, ' = ?'
    );
    PREPARE fetch_parent FROM @stm;

    REPEAT
        EXECUTE fetch_parent USING @parent;

        IF result_in_var THEN
            -- Если result_in_var истинно, то результат сохраняем в result_ids.
            SET result_ids = CONCAT(result_ids, IF(LENGTH(result_ids), ',', ''), @parent);
        ELSE
            -- Иначе сохраняем в локальной переменной.
            SET ids = CONCAT(ids, IF(LENGTH(ids), ',', ''), @parent);
        END IF;

        SET currlevel = currlevel + 1;
    UNTIL (NOT @parent OR currlevel > max_levels) END REPEAT;

    DROP PREPARE fetch_parent;

    IF NOT result_in_var THEN
        -- Если результат не в переменной — вернем рекордсет.
        SET @stm = CONCAT(
            'SELECT ', name_id, ' FROM ', name_table,
            ' WHERE ', name_id, ' IN (', ids, ')'
        );

        PREPARE fetch_parents FROM @stm;
        EXECUTE fetch_parents;
        DROP PREPARE fetch_parents;
    END IF;
END;

Мне необходима обратная операция - выборка всех потомков узла.
Сложность в том, что у узла может быть несколько потомков, а не один(как в случае с предком). В вышеприведенной ХП на каждой итерации цикла выполнялся запрос на выбор предка и было точно известно, что вернется одна запись. А как обрабатывать результат, если вернется несколько записей?
В InterBase есть конструкция FOR EACH ROW (или как-то так), в MySQL такого нет.
Посоветовали использовать курсоры, но я не особо их понял + было бы неплохо передавать название таблицы и столбцов в качестве параметров, что еще усложняет написание.

Помогите составить процедуру.
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 01-05-2011 16:16 » 

Rifler, я все таки не понимаю, что тебе надо. Ведь статья как раз и посвящена данному вопросу...

И код там же приведен:

Код: (MySQL)
CREATE PROCEDURE fetch_subtree_ids(
    IN name_table VARCHAR(64),
    IN name_id VARCHAR(64),
    IN name_parent VARCHAR(64),
    IN base INT UNSIGNED,
    IN max_levels INT,
    IN result_in_var BOOLEAN,
    OUT result_ids MEDIUMTEXT
)
BEGIN
    DECLARE ids MEDIUMTEXT DEFAULT '';
    DECLARE currlevel INT DEFAULT 0;

    SET @parents = base;

    IF result_in_var THEN
        SET result_ids = '';
    END IF;

    -- В случае если max_levels равно 0, то допускаем 100000 уровней.
    -- Отрицательные значения дадут один уровень — это побочное явление.
    SET currlevel = IF(max_levels, 1, -100000);

    REPEAT
        -- Внимание! Значение base тоже входит в результат.
        IF result_in_var THEN
            -- Если result_in_var истинно, то результат сохраняем в result_ids.
            SET result_ids = CONCAT(result_ids, IF(LENGTH(result_ids), ',', ''), @parents);
        ELSE
            -- Иначе сохраняем в локальной переменной.
            SET ids = CONCAT(ids, IF(LENGTH(ids), ',', ''), @parents);
        END IF;

        SET @stm = CONCAT(
            'SELECT GROUP_CONCAT(', name_id, ') INTO @parents FROM ', name_table,
            ' WHERE ', name_parent, ' IN (', @parents, ')'
        );

        PREPARE fetch_childs FROM @stm;
        EXECUTE fetch_childs;
        DROP PREPARE fetch_childs;

        SET currlevel = currlevel + 1;
    UNTIL (@parents IS NULL OR currlevel > max_levels) END REPEAT;

    IF NOT result_in_var THEN
        -- Если результат не в переменной — вернем рекордсет.
        SET @stm := CONCAT(
            'SELECT ', name_id, ' FROM ', name_table,
            ' WHERE ', name_id, ' IN (', ids, ')'
        );

        PREPARE fetch_childs FROM @stm;
        EXECUTE fetch_childs;
        DROP PREPARE fetch_childs;
    END IF;
END;

И если в статье все это есть, так в чем же заключается вопрос?...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Rifler
Новенький

ru
Offline Offline

« Ответ #2 : 02-05-2011 09:19 » 

в статье выбираются предки, а мне нужны потомки. У узла может быть несколько потомков одновременно, а не один.
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 02-05-2011 09:24 » 

Rifler, а может тебе стоит прочитать статью еще раз? В этот раз внимательно. А нужный код из статьи, специально для тебя, я привел в предыдущем посте.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Rifler
Новенький

ru
Offline Offline

« Ответ #4 : 02-05-2011 16:23 » 

просто я идиот.
Спасибо. Закройте тему, если можно
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 02-05-2011 19:30 » new

Заходи еще Улыбаюсь
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines