Снова вложенные множества

Alexos

Новичок
Снова вложенные множества

Вот написал метод:
PHP:
        // Метод getTree:
        // выстраивает дерево категорий и
        // возвращает его в переменной $tree
        // Параметры:
        // $otstup int, передаётся отступ вложенной категории относительно родителя
        // $li string, маркер списка (какой угодно html)
        // $root (yes|no), выводить ли в дереве корневую запись

        function getTree($otstup=6, $li="", $root="yes") {
        
                if ($root == "yes") $root = "0";
                else $root = "1";

                $query = "SELECT cid, clevel, title FROM ".$this->ctable." WHERE cid > ".$root." ORDER BY cleft ASC";
                $result = $this->db->query($query);

                while($row = $this->db->fetch_array($result)) {
                   $tree .= str_repeat(" ", $otstup*$row['clevel']).
                            $li."<a href=\"".$_SERVER[$PHP_SELF]."?cid=".$row['cid']."\">".$row['title']."</a><br>";
                } // while
                
                return $tree;

        } //end getTree( )
Но к сожалению, ветки выводятся в порядке как были введены в базу.. собственно согласно предложения запроса ORDER BY cleft
Вопрос: коллеги, как вывести дерево так, чтобы каждая ветка была отсортирована по алфавиту?
 

Demiurg

Guest
>речь идёт о Nested Sets
об этом, мякго говоря, нигде не указывалось в вопросе.
думаю, что тебе нужно
ORDER BY cleft , title
 

Alexos

Новичок
об этом, мякго говоря, нигде не указывалось в вопросе.
об этом указывалось в скрипте.
думаю, что тебе нужно
ORDER BY cleft, title
по твоему в поле cleft могут встречаться одинаковые значения? :):):)
Demiurg, ты знаком с алгоритмом Nested Sets вообще?
 

Demiurg

Guest
>Demiurg, ты знаком с алгоритмом Nested Sets вообще?
не знаком, и в скрипте об этом тоже никаких указаний не было.
 

Alexos

Новичок

Макс

Старожил PHPClub
sql-запросом ты дерево, отсортированное по title, сформировать не сможешь

Я знаю 2 варианта:
1. получить все дерево и уже с помощью ПХП отсортировать как надо.
2. я в форум уже бросал код, как перемещать узел вверх/вниз в пределах одного родителя (ссылка на тему есть в комментах под статьей на http://detail.phpclub.net/article/db_tree). Пусть с помощью этих перемещений админ выстраивает порядок как должны выводиться узлы в дереве.
 

Alexos

Новичок
2. я в форум уже бросал код, как перемещать узел вверх/вниз в пределах одного родителя (ссылка на тему есть в комментах под статьей на http://detail.phpclub.net/article/db_tree). Пусть с помощью этих перемещений админ выстраивает порядок как должны выводиться узлы в дереве.
Ты имеешь ввиду метод MoveAll?
1. получить все дерево и уже с помощью ПХП отсортировать как надо.
Можно кусочек кода с комментами.. если честно не совсем представляю как это реализовать..
 

Макс

Старожил PHPClub
Можно кусочек кода с комментами.. если честно не совсем представляю как это реализовать..
я такого не писал (но сделать это вполне реально)

Нет, я не про moveAll а про код из этой темы
 

Макс

Старожил PHPClub
код из той темы меняет порядок узлов внутри одного родителя.
MoveAll просто перемещает узел в другое место, но никак не управляет порядком. MoveAll поместит узел последним, для указанного parent_id
 

Alexos

Новичок
код из той темы меняет порядок узлов внутри одного родителя.
ок. я понял.
Код из той темы сложноват для восприятия :)
Какие параметры должны передаваться в него? и тогда начну разбираться с ним..
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Автор оригинала: Alexos
Код из той темы сложноват для восприятия :)
Не могу удержаться от любимого прикола и не привести решение на PL/PgSQL
Код:
CREATE OR REPLACE FUNCTION rubric_swap (text, text)
RETURNS VOID 
AS'
DECLARE
    id1     ALIAS FOR $1;
    id2     ALIAS FOR $2;
    rec1    RECORD;
    rec2    RECORD;
    l_one   integer;
    r_one   integer;
    l_two   integer;
    r_two   integer;
    -- these will hold ids
    first   text := '''';
    second  text := '''';
    middle  text := '''';
BEGIN
    -- dont bother
    IF id1 = id2 THEN
        RETURN NULL;
    END IF;
    -- get parent of first element, error out if none
    SELECT my.rubric_left AS l, my.rubric_right AS r, p.rubric_id AS parent INTO rec1
    FROM rubrics my, rubrics p
    WHERE my.rubric_id = id1 AND
          p.rubric_left < my.rubric_left AND
          p.rubric_right > my.rubric_right
    ORDER BY p.rubric_right
    LIMIT 1;
    IF NOT FOUND THEN
        RAISE EXCEPTION ''cannot find parent for %'', id1;
    END IF;
    -- get parent of second element, error out if none
    SELECT my.rubric_left AS l, my.rubric_right AS r, p.rubric_id AS parent INTO rec2
    FROM rubrics my, rubrics p
    WHERE my.rubric_id = id2 AND
          p.rubric_left < my.rubric_left AND
          p.rubric_right > my.rubric_right
    ORDER BY p.rubric_right
    LIMIT 1;
    IF NOT FOUND THEN
        RAISE EXCEPTION ''cannot find parent for %'', id2;
    END IF;
    -- error out if not on the same branch (XXX: is this really needed?)
    IF rec1.parent <> rec2.parent THEN
        RAISE EXCEPTION ''rubrics % and % should be on the same branch'', id1, id2;
    END IF;
    IF rec1.l < rec2.l THEN
        l_one := rec1.l;
        r_one := rec1.r;
        l_two := rec2.l;
        r_two := rec2.r;
    ELSE
        l_one := rec2.l;
        r_one := rec2.r;
        l_two := rec1.l;
        r_two := rec1.r;
    END IF;
    FOR rec1 IN 
        SELECT rubric_id AS id, rubric_left AS l, rubric_right AS r 
        FROM rubrics WHERE rubric_left >= l_one AND rubric_right <= r_two FOR UPDATE 
    LOOP
        -- first branch
        IF rec1.r <= r_one THEN
            first := first || CASE WHEN first <> '''' THEN '', '' ELSE '''' END || quote_literal(rec1.id);
        -- second branch
        ELSIF rec1.l >= l_two THEN
            second := second || CASE WHEN second <> '''' THEN '', '' ELSE '''' END || quote_literal(rec1.id);
        -- elements between branches, when needed
        ELSIF (r_one - l_one) <> (r_two - l_two) THEN
            middle := middle || CASE WHEN middle <> '''' THEN '', '' ELSE '''' END || quote_literal(rec1.id);
        END IF;
    END LOOP;
    EXECUTE ''UPDATE rubrics SET rubric_left = rubric_left + '' || quote_literal(r_two - r_one) || '', rubric_right = rubric_right + '' || quote_literal(r_two - r_one) || '' WHERE rubric_id IN ( '' || first || '' )'';
    EXECUTE ''UPDATE rubrics SET rubric_left = rubric_left - '' || quote_literal(l_two - l_one) || '', rubric_right = rubric_right - '' || quote_literal(l_two - l_one) || '' WHERE rubric_id IN ( '' || second || '' )'';
    IF middle <> '''' THEN
        EXECUTE ''UPDATE rubrics SET rubric_left = rubric_left + '' || quote_literal((r_two - l_two) - (r_one - l_one)) || '', rubric_right = rubric_right + '' || quote_literal((r_two - l_two) - (r_one - l_one)) || '' WHERE rubric_id IN ( '' || middle || '' )'';
    END IF;
    RETURN NULL;
END;
'LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY DEFINER;
 

Макс

Старожил PHPClub
хмм, все-таки ИМХО выгружать все дерево и сортировать его на ПХП более правильно (правда не знаком с твоей задачей)

По поводу кода:
id - узел который будет перемещаться
direction - куда узел будет перемещаться (вверх или вниз). Может иметь 2 значения - 'up' и 'down'
 
Сверху