Модераторы: skyboy
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Обход дерева. MySQL v5.5 
:(
    Опции темы
tishaishii
Дата 7.10.2011, 06:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: нет
Всего: 8



T(ID, PARENT)

Нужно получить скаляр с перечислением всех T.ID - "веток" данного T.ID=?IN_ID.
Описал рекурсивную функцию с результатом group_concat(distinct id separator ?V_SEP). Говорит, нельзя использовать рекурсию.
Описал функцию с временной таблицей без рекурсии. Уткнулся в сообщение о том, что невозможно открыть временную таблицу на чтение и запись одновременно.

Нужна функция, возвращающая список идентификаторов, разделённых ?V_SEP.

Это сообщение отредактировал(а) tishaishii - 7.10.2011, 07:03
PM MAIL ICQ Skype   Вверх
Akina
Дата 7.10.2011, 08:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Nested set + group_concat


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
tishaishii
Дата 7.10.2011, 19:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: нет
Всего: 8



Расскажите подробнее о задумке.
Вот есть дерево с произвольным количеством прямых потомков каждого из узлов.
Как можно получить скаляр со списком потомков данного узла?
PM MAIL ICQ Skype   Вверх
gcc
Дата 7.10.2011, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 3
Всего: 17



tishaishii, дерево большое само или маленькое?

для маленького дерева (как в большинства случаев) можно написать обычную рекурсию на ЯП. Если что, то данные прокэшировать, чтобы не делать большое количество лишних запросов.

а если база большая и само дерево большое, у котором много узлов и детей, то тогда искать другие решения...



рекурсия:
Код

sub section_tree : Privat {
    my ( $self, $c, $sc, $privat ) = @_;

    my $sql2;
    my $sql;
    my $sql_sel;

    if ( !$c->check_user_roles('moder_se') ) {

        $sql2 = 'AND active_se = 1
                     AND forbi_section_se = 0
                     AND active_se = 1';

        $sql = 'AND t1.active_se = 1
                     AND t1.forbi_section_se = 0
                     AND t1.active_se = 1';

        $sql_sel = ', close_se,
                               hiden_g_co';
    }
    else {
        $sql_sel = ', active_se,
                               close_se,
                               forbi_section_se,
                               forbi_content_se,
                               hiden_g_co';

    }

    my $loop_select;
    my $loop_data;
    my $pn;
    my $pn_id;
    my $sqle;

    if ($sc) {

        my $index = 0;
        my @head  = ();
        my $dbh   = $c->model('DBI')->dbh;
        my $sth;
        while (1) {

            $index++;

            $sth = $dbh->prepare( "
        SELECT t1.parent_se_id,
                 t1.id_se,
                 t1.name_se     
          FROM section AS t1
    
         WHERE t1.id_se = ? 
              " . ( $sql || '' ) . "
         LIMIT 1
      " );

            if ( $head[-1] ) {
                $sqle = $head[-1];
            }
            else {
                $sqle = $sc;
            }

            $sth->execute($sqle);

            my $name_parrent = $sth->fetchrow_hashref();
            $sth->finish();

            if ( $name_parrent->{parent_se_id} == 0 ) {
                $name_parrent->{name_se} =
                  'The upper level of the tree';
            }

            $sth = $dbh->prepare( "
        SELECT id_se,
                 name_se,
                 parent_se_id
                 $sql_sel
                              
          FROM section
         WHERE parent_se_id = ? 
              " . ( $sql2 || '' ) . "
      " );

            my $sqle;

            if ( $head[-1] ) {
                $sqle = $head[$#head];
            }
            else {
                $sqle = $sc;
            }

            $sth->execute($sqle);

            my $loop;

            my $ref_and;

            while ( my $ref = $sth->fetchrow_hashref() ) {

                if ( $c->check_user_roles('moder_se') ) {
                    $ref->{close_se}  = $ref->{close_se} == 1  ? '1' : undef;
                    $ref->{active_se} = $ref->{active_se} == 0 ? '1' : undef;
                    $ref->{forbi_section_se} =
                      $ref->{forbi_section_se} == 1 ? '1' : undef;
                    $ref->{forbi_content_se} =
                      $ref->{forbi_content_se} == 1 ? '1' : undef;
                    $ref->{hiden_g_co} = $ref->{hiden_g_co} == 1 ? '1' : undef;
                }

                if (   $ref->{id_se}
                    && $pn_id->[-1]
                    && $ref->{id_se} eq $pn_id->[-1] )
                {

                    $ref_and = $ref;
                    next;
                }

                push( @{$loop}, $ref );

            }
            $sth->finish();

            my $no_select;

            if ($ref_and) {
                unshift @{$loop}, { %{$ref_and} };
            }

            if ( !$loop ) {

                $no_select = 1;
                $loop      = 0;
            }

            my $no_no_select;
            if ( $sc eq $name_parrent->{id_se} ) {
                $no_no_select = 1;
            }

            my %select;

            if ( !$no_select ) {
                $select{SELECT} = $loop;
            }

            push(
                @{$loop_select},
                {
                    NO_NO_SELECT => $no_no_select,
                    %select,
                    NO_SELECT => $no_select,
                    NAME      => $name_parrent->{name_se},
                    NUMBER    => $index
                }
            );

            push @head, $name_parrent->{parent_se_id};

            push @{$pn},    $name_parrent->{name_se};
            push @{$pn_id}, $name_parrent->{id_se};

            my $id = $name_parrent->{id_se};

            last if ( $id eq '1' || $id eq '35' || $index > 20 );

        }

    }

    if ($sc) {
        if ($loop_select) {
            @{$loop_select} = reverse @{$loop_select};
            $c->stash->{loop_select} = $loop_select;
        }
        else {
            $c->stash->{no_loop_select} = 1;
        }
    }

    if ($loop_data) {
        $c->stash->{select_section} = $loop_data;
    }
    else {
        $c->stash->{no_select_section} = 1;
    }

    $c->stash->{selecting}    = $pn->[0];
    $c->stash->{selecting_id} = $pn_id->[0];

}



Добавлено через 4 минуты и 45 секунд
про Nested set
http://webscript.ru/stories/04/09/01/8197045

Цитата

3. Выбор родительской "ветки":

SELECT id, name, level FROM my_tree WHERE left_key <= $left_key AND right_key >= $right_key ORDER BY left_key

В итоге получаем:
• Узел 1
• • Узел 3
• • • Узел 7




вот давно нашел статью:
(не много по другому сделано)
http://habrahabr.ru/blogs/perl/65495/

вот есть на триггерах:
http://habrahabr.ru/blogs/mysql/63883/
http://habrahabr.ru/blogs/postgresql/63416/

не много старые
http://doc.prototypes.ru/database/nestedsets/perl/module/
http://webscript.ru/stories/04/09/01/8197045

Это сообщение отредактировал(а) gcc - 7.10.2011, 22:21
PM WWW ICQ Skype GTalk Jabber   Вверх
tishaishii
Дата 8.10.2011, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: нет
Всего: 8



В том-то дело, что на ЯП создать проблемы нет.
Хочется понять, есть ли возможность в MySQL с помощью SQL создать функцию, работающую с деревьями.
Таблица T(ID, PARENT) дана.
PM MAIL ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0512 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.