Forum Webscript.Ru
Общие => Базы данных => Тема начата: Phoinix от 21 Июля 2004, 18:30:18
-
Есть дерево Nested Set
Что бы переместить один узел на одну позицию выше (ниже) на том же уровне приходится делать несколько лишних манипуляций, а точнее:
1. Выбираем узел который перемещаем:
SELECT left_key, right_key, level FROM table WHERE id = $id
получаем: $left_key, $right_key и $level
2. Выбираем узел который выше по порядку (ниже - запрос аналогичен):
SELECT left_key, right_key FROM table WHERE right_key = $left_key - 1 AND level = $level
получаем: $left_key_up и $right_key_up
Получаем смещения ключей каждого узла:
$skew1 = $right_key - $left_key + 1
$skew2 = $right_key_up - $left_key_up + 1
Теперь, казалось бы, что можно просто в первой ветке уменьшить значения ключей на смещение ключей второй ветки, а во второй увеличить ключи на смещение ключей первой, но данная операция производится в два запроса и во время второго запроса меняются записи которые были уже изменены в первом. Поэтому приходится предварительно выбирать все идентификаторы подчиненных узлов перемещаемого узла, и делать изменения не относительно ключей а относительно идентификаторов:
3. Выбираем идентификаторы:
SELECT id FROM table WHERE left_key >= $left_key AND right_key <= $right_key
получаем: $id_move
4. Меняем ключи второго узла:
UPDATE table SET left_key = left_key - $skew1, right_key = right_key - $skew1 WHERE left_key >= $left_key_up AND right_key <= $right_key_up
5. Меняем ключи перемещаемого узла:
UPDATE table SET left_key = left_key + $skew2, right_key = right_key + $skew2 WHERE id IN ($id_move)
Возможно ли упростить данную операцию?
-
В голову приходит только объединение 1 и 3 запроса в один:
SELECT t1.id, t2.left_key, t2.right_key, t2.level
FROM table AS t1, table AS t2
WHERE t2.id = 20 AND t1.left_key >= t2.left_key AND t1.right_key <= t2.right_key
но при этом логика остается той же...
-
перемещение узлов происходит не так часто чтобы его оптимизировать.
Не пробовал объединить выборку всех идентификаторов, которые нужно переместить и само перемещение? То есть вместо запросов
SELECT id FROM table WHERE left_key >= $left_key AND right_key <= $right_key
и
UPDATE table SET left_key = left_key + $skew2, right_key = right_key + $skew2 WHERE id IN ($id_move)
Делать один, что-то вроде :
UPDATE table SET left_key = left_key + $skew2, right_key = right_key + $skew2 WHERE
left_key >= $left_key AND right_key <= $right_key
-
твой код основан на
http://phpclub.ru/talk/showthread.php?s=&threadid=30774&perpage=20&pagenumber=2
?
Если да, то он писался давно и тогда я еще не совсем разобрался с Nested Sets
-
Макс
твой код основан на
Нет... честно говоря, это не видел...
Не пробовал объединить выборку всех идентификаторов, которые нужно переместить и само перемещение? То есть вместо запросов
В том-то и дело, что пробовал, но при перемещении первой ветки (не зависимо от какой) ключи очень часто попадают в диапазон выборки второго запроса, Например:
Ветка 1 [1][1][6]
Ветка 1-1 [2][2][3]
Ветка 1-2 [2][4][5]
Ветка 2 [1][7][12]
Ветка 2-1 [2][8][9]
Ветка 2-2 [2][10][11]
Нужно "Ветку 2" поднять выше "Ветки 1"
При обновлении ключей "Ветки 2" получается:
Ветка 1 [1][1][6]
Ветка 1-1 [2][2][3]
Ветка 1-2 [2][4][5]
Ветка 2 [1][1][6]
Ветка 2-1 [2][2][3]
Ветка 2-2 [2][4][5]
И если мы захотим сделать обновление ключей "Ветки 1", то мы уже не можем брать в запросе диапазон ключей "Ветки 1" т.к. В него попадут узлы "Ветки 2"
P.S. Появилась новая мысль... попробую проверить ... :)
-
Т.к. пользуюсь DBI то решил сначала выбрать SELECT обе ветки в разные массивы, а потом обработать, но так получается еще медленней... Но впрочем это не так важно, и так работает, тем более действительно перемещение узлов не такая частая процедура...
-
Попробовал все как ты сказал, phoinix.
Перемещение вниз
Получилось так
//Выбираем узел который перемещаем:
$sql = "SELECT * FROM c_tree WHERE id=$parent_id";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
$left_key = $row[\'left_key\'];
$right_key = $row [\'right_key\'];
$level = $row[\'level\'];
$page_id = $row[\'page_id\'];
$p_parent_id = $row[\'parent_id\'];
//Выбираем узел который ниже по порядку
$sql = "SELECT * FROM c_tree WHERE left_key = $right_key + 1 AND level = $level";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
$left_key_down = $row[\'left_key\'];
$right_key_down = $row [\'right_key\'];
//Получаем смещения ключей каждого узла:
$skew1 = $right_key - $left_key + 1;
$skew2 = $right_key_down - $left_key_down + 1;
//Выбираем идентификаторы:
$sql = "SELECT * FROM c_tree WHERE left_key >= $left_key AND right_key <= $right_key";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
$id_move = $row [\'id\'];
//Меняем ключи второго узла
$sql = "UPDATE c_tree SET left_key = left_key - $skew1, right_key = right_key - $skew1 WHERE left_key >= $left_key_down AND right_key <= $right_key_down";
$res = mysql_query($sql);
//Меняем ключи перемещаемого узла:
$sql = "UPDATE c_tree SET left_key = left_key + $skew2, right_key = right_key + $skew2 WHERE id IN ($id_move)";
$res = mysql_query($sql);
Все рботет, если у той записи,кот. мы перемещеаем и последующей нету потомков. Если есть, то все литит в трубу. В чем может быть проблема?
-
slash2k
http://www.webscript.ru/stories/05/01/24/6319028