Автор Тема: Nested Set Поменять ветки местами на одном уровне  (Прочитано 5264 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Phoinix

  • RW
  • Ветеран
  • *****
  • Сообщений: 1097
  • +0/-0
  • 2
    • Просмотр профиля
    • http://phoinix.ucoz.ru
Есть дерево 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)

Возможно ли упростить данную операцию?

Оффлайн Phoinix

  • RW
  • Ветеран
  • *****
  • Сообщений: 1097
  • +0/-0
  • 2
    • Просмотр профиля
    • http://phoinix.ucoz.ru
В голову приходит только объединение 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

но при этом логика остается той же...

Оффлайн Макс

  • vir magni ingenii
  • Глобальный модератор
  • Ветеран
  • *****
  • Сообщений: 3534
  • +0/-0
  • 2
    • Просмотр профиля
перемещение узлов происходит не так часто чтобы его оптимизировать.

Не пробовал объединить выборку всех идентификаторов, которые нужно переместить и само перемещение? То есть вместо запросов

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
First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack. ( George Carrette )

Оффлайн Макс

  • vir magni ingenii
  • Глобальный модератор
  • Ветеран
  • *****
  • Сообщений: 3534
  • +0/-0
  • 2
    • Просмотр профиля
твой код основан на
http://phpclub.ru/talk/showthread.php?s=&threadid=30774&perpage=20&pagenumber=2
?

Если да, то он писался давно и тогда я еще не совсем разобрался с Nested Sets
First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack. ( George Carrette )

Оффлайн Phoinix

  • RW
  • Ветеран
  • *****
  • Сообщений: 1097
  • +0/-0
  • 2
    • Просмотр профиля
    • http://phoinix.ucoz.ru
Макс
Цитировать
твой код основан на

Нет... честно говоря, это не видел...

Цитировать
Не пробовал объединить выборку всех идентификаторов, которые нужно переместить и само перемещение? То есть вместо запросов


В том-то и дело, что пробовал, но при перемещении первой ветки (не зависимо от какой) ключи очень часто попадают в диапазон выборки второго запроса, Например:


Ветка 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. Появилась новая мысль... попробую проверить ... :)

Оффлайн Phoinix

  • RW
  • Ветеран
  • *****
  • Сообщений: 1097
  • +0/-0
  • 2
    • Просмотр профиля
    • http://phoinix.ucoz.ru
Т.к. пользуюсь DBI то решил сначала выбрать SELECT обе ветки в разные массивы, а потом обработать, но так получается еще медленней... Но впрочем это не так важно, и так работает, тем более действительно перемещение узлов не такая частая процедура...

Оффлайн slash2k

  • Заглянувший
  • Новичок
  • *
  • Сообщений: 9
  • +0/-0
  • 0
    • Просмотр профиля
    • http://
Nested Set Поменять ветки местами на одном уровне
« Ответ #6 : 26 Сентября 2005, 23:34:20 »
Попробовал все как ты сказал, 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);



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

Оффлайн Phoinix

  • RW
  • Ветеран
  • *****
  • Сообщений: 1097
  • +0/-0
  • 2
    • Просмотр профиля
    • http://phoinix.ucoz.ru

 

Sitemap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28