WebScript.Ru
C:\   главная  ::   о сайте  ::  каталог скриптов  ::  гнездо  ::  форум  ::   авторам  :: Новостройки ::   ХОСТИНГ  ::

|| разделы::
|| поиск по сайту::

|| реклама::
|| новости почтой::
Рассылки Subscribe.Ru ::



Новости сайта WebScript.Ru
Популярные статьи

Hot 5 Stories

|| рекомендуем::




Деревья Nested Sets


Прислал: LSD^ [ 22.10.2003 @ 16:45 ]
Раздел:: [ Статьи по PHP ]


Для начала нужно обязательно сходить и прочесть статью //myphp.net.ru/lessons/index.php?18 Это введение в деревья использующие алгоритм Nested Sets и необходимая и пользовая теория. Вкратце можно сказать что деревья используются в таблицах хранящих категории товаров неограниченной вложенности или например структуру всего сайта или структуру директорий на вашем винте и т.д. Всю эту прелесть можно хранить в одной таблице и ею довольно легко манипулировать.

Для создания и работы с деревьями Nested Sets написан класс CDBTree, качать его нугено тута. Вообщем все нужное вы найдете на //www.e-taller.net/dbtree/ Не буду вдаваться в теорию, далее будет представлен код и основные методы работы с этим типом дерева.

Итак... будем считать что теория прочитана и сейчас главное разобраться с SQL запросами. Для удобства заводим две функции: для коннекта к базе и для вывода дерева. И потом засылаем запросы к базе. Кусок IF (A.cat_left+1 < A.cat_right, 1, 0) AS nflag дает нам 1 если элемент дерева имеет потомков, иначе 0.

Для работы всех примеров используется уже готовое дерево Nested Sets - таблица molotok её дамп тута, настройки базы в фукции connect_db(). Если вы создадите свою табицу или она у вас уже есть, то её название в переменной $tbl. Исходники всех примеров тута, вы можете их скачать и погонять на своем тазике :))

Первый пример (ns_test1.php)
Основные методы работы с деревом.

<?php

function connect_db()
{
    
mysql_connect("localhost", "root", "") or die("Can`t connect");
    
mysql_select_db("bidz") or die("Can`t select");
}

function
print_rez($query, $text="")
{
    
$result = mysql_query($query);
    if (
mysql_num_rows($result) == 0) die("Empty result or Bad sql: ".$query);
    echo (!empty(
$text) ? "<P><B>".$text."</B><BR>n" : "<P>n").$query."<P>n";
    while (
$row = mysql_fetch_assoc($result))
        echo
str_repeat("&nbsp; &nbsp; &nbsp;",    $row['cat_level']).
            
" [".$row['cat_id']."] ". ((isset($row['nflag']) && $row['nflag']) ? "<b>".$row['cat_name']."</b>" : $row['cat_name']).
            
" <font color='#0033FF'>[".$row['cat_left']."]</font> ".
            
" <font color='#009900'>[".$row['cat_right']."]</font> (".$row['cat_level'].") <br>";
}

$tbl = "molotok";
connect_db();


// Выводим все дерево
//
$query = "SELECT *, IF (cat_left+1 < cat_right OR cat_level = 1, 1, 0) AS nflag FROM ".$tbl." ORDER BY cat_left";
print_rez($query, "Выводим все дерево");


// Выводим всех родителей
//
$id = 65; // id нужного элемента
$query = "SELECT A.*, IF (A.cat_left+1 < A.cat_right, 1, 0) AS nflag FROM ".$tbl." A, ".$tbl." B WHERE B.cat_id='".$id."' AND B.cat_left BETWEEN A.cat_left AND A.cat_right ORDER BY A.cat_left";
print_rez($query, "Выводим всех родителей для элемента: ".$id);


// Выводим нужную ветку
//
$id = 14; // id нужного элемента
$query = "SELECT A.*, IF (A.cat_left+1 < A.cat_right, 1, 0) AS nflag FROM ".$tbl." A, ".$tbl." B WHERE B.cat_id='".$id."' AND A.cat_left >= B.cat_left AND A.cat_right <= B.cat_right ORDER BY A.cat_left";
print_rez($query, "Выводим ветку для элемента: ". $id);


//Выводим "приоткрытое" дерево
//
$ncat = 44; // id нужного элемента
$query = "SELECT A.* FROM ".$tbl." A, ".$tbl." B WHERE B.cat_id = '".$ncat."' AND B.cat_left BETWEEN A.cat_left AND A.cat_right ORDER BY A.cat_left";
$result = mysql_query($query);
if ((
$alen = mysql_num_rows($result)) == 0) die("Err!");
$i = 0;
$sql = "";

while (
$row = mysql_fetch_assoc($result))
{
    if ((++
$i == $alen) && ($row['cat_left']+1 == $row['cat_right'])) break;
    
$sql .= " OR (cat_level=".($row['cat_level']+1)." AND cat_left>".$row['cat_left']." AND cat_right<".$row['cat_right']. ")";
}

$sql = "SELECT *, IF (cat_left+1 < cat_right OR cat_level = 1, 1, 0) AS nflag FROM ".$tbl." WHERE cat_level=1 ".$sql." ORDER BY cat_left";
print_rez($sql, "Выводим "приоткрытое" дерево для элемента: ". $ncat);

?>

Запускаем все это дело и видим нужный нам результат...

Выводим все дерево
SELECT *, IF (cat_left+1 < cat_right OR cat_level = 1, 1, 0) AS nflag FROM molotok ORDER BY cat_left

[1] [1] [132] (0)
      [2] Книги, Видео, Музыка, CD [2] [63] (1)
           [3] Журналы и газеты [3] [4] (2)
           [4] Видео [5] [28] (2)
                [21] Видеодиски [6] [13] (3)
                     [33] Комедии, Мелодрамы [7] [8] (4)
                     [34] Семейное и детское кино [9] [10] (4)
                     [35] Фантастика, Мистика, Ужасы [11] [12] (4)
                [22] DVD-диски [14] [15] (3)
                [23] Видеокассеты с неигровыми записями [16] [17] (3)
                [24] Видеокассеты с зарубежными фильмами [18] [25] (3)
                     [36] Комедии, Мелодрамы [19] [20] (4)
                     [37] Семейное и детское кино [21] [22] (4)
                     [38] Фантастика, Мистика, Ужасы [23] [24] (4)
                [25] Видеокассеты с фильмами без перевода [26] [27] (3)
           [5] Книги [29] [58] (2)
                [26] Художественная литература [30] [31] (3)
                [27] Детская литература [32] [33] (3)
                [28] Дом, Семья, Досуг [34] [35] (3)
                [29] Естественные науки [36] [37] (3)
                [30] Искусство, искусствоведение [38] [39] (3)
                [31] Компьютеры, Программирование, Интернет [40] [55] (3)
                     [60] PHP [41] [48] (4)
                          [64] For Lammotz [42] [43] (5)
                          [65] For Coders [44] [45] (5)
                          [66] RTFM etc. [46] [47] (5)
                     [61] C/C++/C# [49] [50] (4)
                     [62] Delphi [51] [52] (4)
                     [63] Other shit [53] [54] (4)
                [32] На иностранных языках [56] [57] (3)
           [6] Мультимедийные издания [59] [60] (2)
           [7] Музыка [61] [62] (2)
      [8] Коллекционирование [64] [129] (1)
           [9] Вещи знаменитостей, Автографы [65] [66] (2)
           [10] Военные вещи [67] [68] (2)
           [11] Игры: MtG, Pokemon и другие [69] [70] (2)
           [12] Киндер Сюрприз [71] [72] (2)
           [13] Коллекционное оружие [73] [74] (2)
           [14] Банкноты [75] [100] (2)
                [39] Австралия и Океания [76] [77] (3)
                [40] Азия [78] [79] (3)
                [41] Америка [80] [81] (3)
                [42] Россия и СССР [82] [93] (3)
                     [54] Госвыпуски до 1917 [83] [84] (4)
                     [55] Госвыпуски после 1917 [85] [86] (4)
                     [56] Лотереи, акции, облигации [87] [88] (4)
                     [57] Частные выпуски до 1922 [89] [90] (4)
                     [58] Частные выпуски после [91] [92] (4)
                [43] Африка [94] [95] (3)
                [44] Европа [96] [97] (3)
                [45] Страны СНГ [98] [99] (3)
           [15] Модели [101] [102] (2)
           [16] Открытки [103] [104] (2)
           [17] Спортивные карточки [105] [106] (2)
           [18] Жетоны, Медали, Значки [107] [124] (2)
                [46] Жетоны [108] [109] (3)
                [47] Памятные медали и знаки, Значки [110] [111] (3)
                [48] Воинские награды и знаки отличия [112] [121] (3)
                     [50] Россия до 1917 г. [113] [114] (4)
                     [51] Россия и СНГ после 1991 г. [115] [116] (4)
                     [52] СССР с 1917 до 1991 г. [117] [118] (4)
                     [53] Другие страны [119] [120] (4)
                [49] Памятные медали и знаки, Значки [122] [123] (3)
           [19] Фотографии, Письма [125] [126] (2)
           [20] Марки [127] [128] (2)
      [59] Услуги [130] [131] (1)

Выводим всех родителей для элемента: 65
SELECT A.*, IF (A.cat_left+1 < A.cat_right, 1, 0) AS nflag FROM molotok A, molotok B WHERE B.cat_id='65' AND B.cat_left BETWEEN A.cat_left AND A.cat_right ORDER BY A.cat_left

[1] [1] [132] (0)
      [2] Книги, Видео, Музыка, CD [2] [63] (1)
           [5] Книги [29] [58] (2)
                [31] Компьютеры, Программирование, Интернет [40] [55] (3)
                     [60] PHP [41] [48] (4)
                          [65] For Coders [44] [45] (5)

Выводим ветку для элемента: 14
SELECT A.*, IF (A.cat_left+1 < A.cat_right, 1, 0) AS nflag FROM molotok A, molotok B WHERE B.cat_id='14' AND A.cat_left >= B.cat_left AND A.cat_right <= B.cat_right ORDER BY A.cat_left

           [14] Банкноты [75] [100] (2)
                [39] Австралия и Океания [76] [77] (3)
                [40] Азия [78] [79] (3)
                [41] Америка [80] [81] (3)
                [42] Россия и СССР [82] [93] (3)
                     [54] Госвыпуски до 1917 [83] [84] (4)
                     [55] Госвыпуски после 1917 [85] [86] (4)
                     [56] Лотереи, акции, облигации [87] [88] (4)
                     [57] Частные выпуски до 1922 [89] [90] (4)
                     [58] Частные выпуски после [91] [92] (4)
                [43] Африка [94] [95] (3)
                [44] Европа [96] [97] (3)
                [45] Страны СНГ [98] [99] (3)

Выводим "приоткрытое" дерево для элемента: 44
SELECT *, IF (cat_left+1 < cat_right OR cat_level = 1, 1, 0) AS nflag FROM molotok WHERE cat_level=1 OR (cat_level=1 AND cat_left>1 AND cat_right<132) OR (cat_level=2 AND cat_left>64 AND cat_right<129) OR (cat_level=3 AND cat_left>75 AND cat_right<100) ORDER BY cat_left

      [2] Книги, Видео, Музыка, CD [2] [63] (1)
      [8] Коллекционирование [64] [129] (1)
           [9] Вещи знаменитостей, Автографы [65] [66] (2)
           [10] Военные вещи [67] [68] (2)
           [11] Игры: MtG, Pokemon и другие [69] [70] (2)
           [12] Киндер Сюрприз [71] [72] (2)
           [13] Коллекционное оружие [73] [74] (2)
           [14] Банкноты [75] [100] (2)
                [39] Австралия и Океания [76] [77] (3)
                [40] Азия [78] [79] (3)
                [41] Америка [80] [81] (3)
                [42] Россия и СССР [82] [93] (3)
                [43] Африка [94] [95] (3)
                [44] Европа [96] [97] (3)
                [45] Страны СНГ [98] [99] (3)
           [15] Модели [101] [102] (2)
           [16] Открытки [103] [104] (2)
           [17] Спортивные карточки [105] [106] (2)
           [18] Жетоны, Медали, Значки [107] [124] (2)
           [19] Фотографии, Письма [125] [126] (2)
           [20] Марки [127] [128] (2)
      [59] Услуги [130] [131] (1)

Заметьте, что ветки: 2, 42, 18 и 59 не открыты. То есть данный результат получился бы и при выводе для элемента 14. А если бы мы выводили "приоткрытое" дерево для элемента 42, тогда бы добавились его потомки четвертого уровня. Этот фикус можно заюзать для построения навигации по сайту, вообщем поэкспериментируйте. Л

Второй пример (ns_test2.php)
Представим что нам нужно вывести дерево одной таблицей как тут: //molotok.ru/catalog/index.php?MIval=/catalog/default.app Рисуем шаблон для Integrated Template(класс HTML_Template_IT) из PEAR.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>molotok sample</title>
<meta http2-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>

<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<!-- BEGIN t_data -->
  <tr>
    <!-- BEGIN t_inner -->
        <!-- BEGIN _twd --><td width="5%" align="center">*</td><!-- END _twd -->
        <!-- BEGIN _d -->
            <td<!-- BEGIN _ttd --> colspan="{_tcols}"<!-- END _ttd -->><!-- BEGIN _zag --><b>{header}</b><br><!-- END _zag -->
            <!-- BEGIN hdr0 --><a href="{lnk0}">enter category</a><!-- END hdr0 -->
            <!-- BEGIN _data --><!-- BEGIN dlm --> -:- <!-- END dlm --><a href="{lnk}">{tdata}</a><!-- END _data -->
            </td>
        <!-- END _d -->
    <!-- END t_inner -->
  </tr>
<!-- BEGIN t_spacer -->
  <tr>
    <td height="5"<!-- BEGIN _ts --> colspan="{max_lvl}"<!-- END _ts -->></td>
  </tr>
<!-- END t_spacer -->
<!-- END t_data -->
</table>
</body>
</html>

И рисуем код, переменная $max_lvl = 4; //MAX(cat_level) - 1 тоесть она меньше максимального уровня дерева на единицу. Мoжно выставить сразу или дописать вначале запрос и определить.

<?php

function connect_db()
{
    
mysql_connect("localhost", "root", "") or die("Can`t connect");
    
mysql_select_db("bidz") or die("Can`t select");
}


require_once(
"template_it.class.php");
connect_db();
$mod = new IntegratedTemplate();
$mod->loadTemplatefile("tree_tmpl.html");

$tbl = "molotok";
$sql = "SELECT  IF ( A.cat_level = 0, B.cat_left, A.cat_left ) AS cat, A.cat_level, A.cat_name AS name, B.cat_id, B.cat_name FROM ".$tbl." A INNER  JOIN ".$tbl." B ON ( ( B.cat_level = A.cat_level + 1 ) AND ( B.cat_left = B.cat_right - 1 ) AND B.cat_left BETWEEN A.cat_left AND A.cat_right )  WHERE ( A.cat_left != A.cat_right - 1) ORDER BY cat, B.cat_id";
print
$sql."<p>";
$res = mysql_query($sql);
if (
mysql_num_rows($res) == 0) die("Err (2): cat tree!");

//ВНИМАНИЕ $max_lvl требует настройки
$max_lvl
= 4; //MAX(cat_level) - 1
$dlm = false;
$i = 0;
$cat = -1;

while (
$row = mysql_fetch_assoc($res))
{
    if (
$cat != $row['cat'])
    {
        if (++
$i > 1) $mod->parse("t_data");
        
//t_inner
        
$mod->setCurrentBlock("t_inner");

        if (
$row['cat_level'] == 0)
        {
            if (
$max_lvl > 1) $mod->setVariable(array("_tcols" => $max_lvl, "max_lvl" => $max_lvl));
                else
$mod->touchBlock("t_spacer");
            
$mod->setVariable(array("header" => $row['cat_name'], "lnk0" => "?cat=".$row['cat_id']));
            continue;
        }

        
$cols = ($max_lvl + 1) - $row['cat_level'];
        
$dlm = true;
        
$cat = $row['cat'];

        if (
$row['cat_level'] > 1)
            for (
$i = 1; $i <= $row['cat_level']-1; $i++)
            {
                
< font color="#0000BB">$mod
->touchBlock("_twd");
                
< font color="#0000BB">$mod->parse("t_inner");
            }

        if (
$cols > 1) $mod->setVariable("_tcols", $cols);
        
$mod->setVariable("header", $row['name']);
        if (
$max_lvl > 1) $mod->setVariable("max_lvl", $max_lvl); else $mod->touchBlock("t_spacer");
    }

    if (
true) //$lvl < $row['cat_level']
    
{
        
//_data
        
$mod->setCurrentBlock("_data");
        if (
$dlm) $dlm = !$dlm;    else $mod->touchBlock("dlm");
        
$mod->setVariable(array("tdata" => $row['cat_name'], "lnk" => "?cat=".$row['cat_id']));
        
$mod->parse("_data");
    }
}

$mod->show();

?>

Не думаю что SQL запрос идеален, но в принципе он нам подходит. Запускаем всю эту колбасень...

SELECT IF ( A.cat_level = 0, B.cat_left, A.cat_left ) AS cat, A.cat_level, A.cat_name AS name, B.cat_id, B.cat_name FROM molotok A INNER JOIN molotok B ON ( ( B.cat_level = A.cat_level + 1 ) AND ( B.cat_left = B.cat_right - 1 ) AND B.cat_left BETWEEN A.cat_left AND A.cat_right ) WHERE ( A.cat_left != A.cat_right - 1) ORDER BY cat, B.cat_id

Книги, Видео, Музыка, CD
Журналы и газеты -:- Мультимедийные издания -:- Музыка
* Видео
DVD-диски -:- Видеокассеты с неигровыми записями -:- Видеокассеты с фильмами без перевода
* * Видеодиски
Комедии, Мелодрамы -:- Семейное и детское кино -:- Фантастика, Мистика, Ужасы
* * Видеокассеты с зарубежными фильмами
Комедии, Мелодрамы -:- Семейное и детское кино -:- Фантастика, Мистика, Ужасы
* Книги
Художественная литература -:- Детская литература -:- Дом, Семья, Досуг -:- Естественные науки -:- Искусство, искусствоведение -:- На иностранных языках
* * Компьютеры, Программирование, Интернет
C/C++/C# -:- Delphi -:- Other shit
* * * PHP
For Lammotz -:- For Coders -:- RTFM etc.
Коллекционирование
Вещи знаменитостей, Автографы -:- Военные вещи -:- Игры: MtG, Pokemon и другие -:- Киндер Сюрприз -:- Коллекционное оружие -:- Модели -:- Открытки -:- Спортивные карточки -:- Фотографии, Письма -:- Марки
* Банкноты
Австралия и Океания -:- Азия -:- Америка -:- Африка -:- Европа -:- Страны СНГ
* * Россия и СССР
Госвыпуски до 1917 -:- Госвыпуски после 1917 -:- Лотереи, акции, облигации -:- Частные выпуски до 1922 -:- Частные выпуски после
* Жетоны, Медали, Значки
Жетоны -:- Памятные медали и знаки, Значки -:- Памятные медали и знаки, Значки
* * Воинские награды и знаки отличия
Россия до 1917 г. -:- Россия и СНГ после 1991 г. -:- СССР с 1917 до 1991 г. -:- Другие страны
Услуги
enter category

На этом пока все, не судите строго и разрешите откланяться :) Если возникнут вопросы, мыльте, я всем отвечу.




 :::::  tommy пишет 22.10.2003 @ 19:36 
мдя ...
 :::::  Fog пишет 23.10.2003 @ 19:15 
Отличная статья, спасибо!
 :::::  KpoH пишет 24.10.2003 @ 05:06 
=-0))
foreva
 :::::  Pr0Head пишет 29.10.2003 @ 23:43 
Respect!

Неделю голову ломал как сделать подобное.
Статья попалась как нильзя кстати.
 :::::  Николай пишет 05.12.2003 @ 08:17 
А ведь можно решить и проще, используя всего лишь две таблицы, причем SQL запросы выглядять гораздо проще. Хотя такой вариант тоже неплох
 :::::  LSD^ пишет 05.12.2003 @ 16:25 
to Николай

как это решается двумя таблицами? в двух словах...
 :::::  Andrey пишет 17.12.2003 @ 11:25 
Николай! Хватит уже интриг! Алгоритм в студию!
 :::::  idencial пишет 24.01.2004 @ 01:11 
Николай просто не понял пока степень своего наива =)
Всегда умиляли выссказывания, типа "А ведь можно решить и проще" и молчание на предложение подтвердить свои слова
 :::::  LSD^ пишет 25.01.2004 @ 03:39 
to idencial

угу.. забавно однако ~:P :))
 :::::  алекс пишет 01.02.2004 @ 02:33 
отличная статья,
Как раз то что нужно, и когда нужно;)
 :::::  FireBear пишет 09.02.2004 @ 20:22 
Но ведь для графического отображения дерево можно построить за 1 проход в цикле, используя темплейты, я не говорю о построении в памяти... да и запрос будет компактнее, всего то нужно отсортировать. 1 раз селав теперь не откажусь от этого способа.
 :::::  LSD^ пишет 11.03.2004 @ 06:13 
to FireBear

Представим что нам нужно вывести дерево одной таблицей как тут: http://molotok.ru/catalog/index.php?MIval=/catalog/default.app
Пришли свой вариант.

а построение в памяти - куйня :)
 :::::  denis пишет 30.03.2004 @ 11:57 
Vopros. Slogno manipulirovat vetvyami kogda uge derevogotovo? Naprimer perenesti odnu vetku v druguu.
Esli li uge napisanye procedur dlya etogo?

Spasibo :)
 :::::  LSD^ пишет 30.03.2004 @ 15:15 
to denis:

есть метод moveAll()

форум по дереву тут: http://phpclub.ru/talk/showthread.php?s=&threadid=30774&perpage=20&pagenumber=1
 :::::  Игорь пишет 07.05.2004 @ 03:40 
Организовал все иначе - реккурсивной функцией и простыми запросами.
И дорогие мои, у большинства провайдеров mysql не самой последней версии, что конструкцию if поддерживает в sql запросах.
 :::::  SooS пишет 06.07.2004 @ 01:04 
Жаль не наткнулся на это раньше - помню как думал как реализовать =) таак и сделал =) только у мя было ещё жуткое наследование ;)
Вывод писал иначе - одной рекурсивной функцией передавал туда параметры - запрос и уровень вложенности =)
 :::::  Lahesis пишет 22.07.2004 @ 17:50 
Вопрос по самому методу построения деревьев Nested Sets. В случае удаления/перемещения ветви встает задача переиндексации всего дерева, она достаточно сложная и рессурсоемкая. В случае построения деревье в принципу родительского подчинения, поменять родителя, как два пальцы об .... - меняем всего одну цифирь и все ветка улетела куда нужно.
Я только не понял в чем состоит сложность работы с такими деревьями с большой глубиной вложенности, помоему все как раз таки проще и приятнее и запросы на четыре строки ваять не нужно.
И еще, по поводу глубины вложенности деревьев в Nested Sets, здесь то как раз таки она должна быть заранее определена и попытка ее увеличения/уменьшения требут опять таки пересчета всех индексов. А как быть если на конце ветвей содержатся динамические объекты.
Вобщем метод не смотря на кажущуюся сложность действительно сложен :). Я писал складскую базу на простом родительском подчинении все работает значительно проще и изящнее.

А статья действительно толковая. Только ссылки на готовые классы народ балуют. Нефига, своей головой работать надо.
 :::::  LSD^ пишет 23.07.2004 @ 03:12 
Да действительно, при переносе веток нужно переиндексировать все дерево, для этого есть класс, а можно и руками :) В чем же тогда проблема? Мы ведь не редактируем дерево каждые 5 секунд. Это делается очень и очень редко. Алгоритм Nested Sets сложен пока разбираешся, а потом уже все просто как апельсин :) На счет четырех строк - это уже зависит от необходимости. Вы можете написать скрипт который будет работать как "Второй пример (ns_test2.php)"... используя Parent ID... давайте потом поглядим на Ваши запросы :) ??

Кстати, недавно был интересный вопрос - типа как можно из Nested Sets в Parent ID конвертнуть..
Это нужно было для построения дерева жабаскриптом как тут http://www.destroydrop.com/javascripts/tree/
Либа на жабе и пример тут http://www.destroydrop.com/javascripts/tree/dtree.zip
А вот и ответ:

SELECT A.cat_id -1 AS id, A.cat_name, ( IFNULL( B.cat_id, 0 ) -1 ) AS parent_id
FROM molotok A
LEFT JOIN molotok B ON A.cat_left
BETWEEN B.cat_left AND B.cat_right AND B.cat_level = A.cat_level -1
ORDER BY A.cat_left

можно еще так:

SELECT A.cat_id -1 AS id, A.cat_name, B.cat_id -1 AS parent_id
FROM molotok A, molotok B
WHERE A.cat_left
BETWEEN B.cat_left AND B.cat_right AND B.cat_level = A.cat_level -1
ORDER BY A.cat_left

по скорости второй запрос быстрее, но в ентом случае корень в результате отсутствует :)
 :::::  kaa пишет 15.11.2004 @ 19:23 
Млин, создатель дерева, тебе реально лечиться надо. Такого монстра сваял...
по адресу http://nojabrsk.info/service перед вами предстанет ДЕРЕВО на PHP, где вся база - в одной таблице, практически без избыточности, и код занимает от силы килобайта 3-4. Делал сам. Единственное - ограничен уровень вложенности (6).

Нужно - пишите...
 :::::  LSD^ пишет 16.11.2004 @ 12:36 
to kaa:

Енто совсем не монстр и не я его придумал. Это маленькая статейка про Nested Sets, для тех кто понимает зачем это надо. Вот и усе :) Кстати вот еще ссылочка http://www.webscript.ru/stories/04/09/01/8197045
 :::::  Sheeva пишет 04.11.2006 @ 03:23 
А как при таком решении реализовать следующую фишку, если у нас один и тот же раздел относится к 2, 3, или более родительским каталогам ???
 :::::  Olfi пишет 22.01.2007 @ 15:40 
Кароче, давайте говорить откровенно.
Слабые стороны: Добавление, Чтение линии предков, копирование ветки, перемещение ветки
Сильные стороны: удаление , Чтение ветки
 :::::  Olfi пишет 22.01.2007 @ 15:41 
Кароче, давайте говорить откровенно.
Слабые стороны: Добавление, Чтение линии предков, копирование ветки, перемещение ветки
Сильные стороны: удаление , Чтение ветки

с учётом, что IF в мускле не юзается
 :::::  Olfi пишет 22.01.2007 @ 15:42 
Кароче, давайте говорить откровенно.
Слабые стороны: Добавление, Чтение линии предков, копирование ветки, перемещение ветки
Сильные стороны: удаление , Чтение ветки

с учётом, что IF в мускле не юзается
 :::::  Вязьма пишет 28.02.2010 @ 23:11 
Знаю что статья старая, но все же. Не могу реализовать перестановку 2х элементов на одном уровне. т.е. мне нужно поменять 2а пункта местами. Как это можно сделать?
Имя:
Email:
URL

Введите сумму двух чисел девять и одинн (девять+одинн=?)
Запомнить мою информацию

* Html запрещен* Ваш E-mail опубликован не будет.

Copyright © 2000-2001 WebScript.Ru nas@webscript.ru
Design © 2001 by Parallax Design Studio (aka Spectator.ru)
Все торговые марки и авторские права на эту страницу принадлежат их соответствующим владельцам.
Сгенерировано за: 0.0333371