Статья на хабре
Код на SQL Fiddle
Происходит восстановление индексов для значения по id_parent
Для PrestaShop этот код выглядит так:
-- По умолчанию у индексов значение 0, сменим на NULL
alter table pref_category modify nleft int unsigned default null;
alter table pref_category modify nright int unsigned default null;
DELIMITER //
-- Создаём ту самую функцию
DROP FUNCTION IF EXISTS rebuild_nested_set_tree//
CREATE FUNCTION rebuild_nested_set_tree()
RETURNS INT DETERMINISTIC MODIFIES SQL DATA
BEGIN
-- Изначально сбрасываем все границы в NULL
UPDATE pref_category t SET nleft = NULL, nright = NULL;
-- Устанавливаем границы корневым элементам
SET @i := 0;
UPDATE pref_category t SET nleft = (@i := @i + 1), nright = (@i := @i + 1)
WHERE t.id_parent = 0;
forever: LOOP
-- Находим элемент с минимальной правой границей -- самый левый в дереве
SET @id_parent := NULL;
SELECT t.id_category, t.nright FROM pref_category t, pref_category tc
WHERE t.id_category = tc.id_parent AND tc.nleft IS NULL AND t.nright IS NOT NULL
ORDER BY t.nright LIMIT 1 INTO @id_parent, @parent_right;
-- Выходим из бесконечности, когда у нас уже нет незаполненных элементов
IF @id_parent IS NULL THEN LEAVE forever; END IF;
-- Сохраняем левую границу текущего ряда
SET @current_left := @parent_right;
-- Вычисляем максимальную правую границу текущего ряда
SELECT @current_left + COUNT(*) * 2 FROM pref_category
WHERE id_parent = @id_parent INTO @parent_right;
-- Вычисляем длину текущего ряда
SET @current_length := @parent_right - @current_left;
-- Обновляем правые границы всех элементов, которые правее
UPDATE pref_category t SET nright = nright + @current_length
WHERE nright >= @current_left ORDER BY nright;
-- Обновляем левые границы всех элементов, которые правее
UPDATE pref_category t SET nleft = nleft + @current_length
WHERE nleft > @current_left ORDER BY nleft;
-- И только сейчас обновляем границы текущего ряда
SET @i := (@current_left - 1);
UPDATE pref_category t SET nleft = (@i := @i + 1), nright = (@i := @i + 1)
WHERE id_parent = @id_parent ORDER BY id_category;
END LOOP;
-- Возвращаем самый самую правую границу для дальнейшего использования
RETURN (SELECT MAX(nright) FROM pref_category t);
END//
DELIMITER ;
Запускаем переиндексацию:
SELECT rebuild_nested_set_tree();
Вот и все, дерево переиндексировано. Вернем на место значения по умолчанию для индексов, так как с null индексы не работают, их и не должно быть:
alter table pref_category modify nleft int unsigned default 0;
alter table pref_category modify nright int unsigned default 0;