@wiewiorek - prawdopodobnie (nie testowałem dogłębnie tych procedur) poniżej masz kod do przenoszenia gałęzi.
Zapoznałem się bliżej z nested set (nie wiedziałem że istnieje taki model drzewa w sql (IMG:
style_emoticons/default/winksmiley.jpg) i wychodzi na to że jest to bardzo fajna rzecz. Poprzednicy mówili o stosowaniu transakcji - zgadzam się, jednak jeśli tylko użytkownik ma możliwość tworzenia procedur to zarządzanie tym drzewem staje się bajecznie proste. Niestety w tym przypadku nie możemy użyć wyzwalaczy (może gdyby pokombinować, nie wiem).
Przy budowaniu procedur korzystałem z gotowców z
tej strony oraz
tego rozwiązania w przypadku przenoszenia gałęzi.
Templatka z procedurami była przygotowywana dla tabeli "nested_category", dla innych trzeba przepisać nazwę. Tak wygląda użycie:
CALL MOVE_BRANCH('NAZWA','DOKĄD'); -- przenosi gałąź NAZWA do kontenera DOKĄD
CALL ADD_SIBLING('OBOK','NAZWA'); -- tworzy nowy węzeł "NAZWA" obok węzła OBOK
CALL ADD_CHILD('RODZIC','NAZWA'); -- dodaje węzeł NAZWA do kontenera RODZIC
CALL REMOVE_NODE('NAZWA'); -- usuwa węzeł NAZWA wraz z wszystkimi dziećmi
CALL REMOVE_NODE_ONLY('NAZWA'); -- usuwa węzeł NAZWA, dzieci zostają przeniesione poziom wyżej
Templata z procedurami jest taka:
DELIMITER $$
DROP PROCEDURE IF EXISTS `MOVE_BRANCH`$$
CREATE PROCEDURE `MOVE_BRANCH` (IN `$FROM` VARCHAR(20), IN `$TO` VARCHAR(20))
BEGIN
START TRANSACTION;
/* cat_b.lft + 1 is the destination. */
SELECT @destination := (lft + 1) FROM nested_category WHERE name = `$TO`;
SELECT @cat_a_width := ((rgt - lft) + 1) FROM nested_category WHERE name = `$FROM`;
/* Rip this table a new cat_a sized hole inside cat_b. */
UPDATE nested_category SET rgt = rgt + @cat_a_width WHERE rgt >= @destination;
UPDATE nested_category SET lft = lft + @cat_a_width WHERE lft >= @destination;
SELECT @cat_a_lft := lft, @cat_a_rgt := rgt FROM nested_category WHERE name = `$FROM`;
SELECT @diff := @destination - @cat_a_lft;
/* Move cat_a and all inhabitants to new hole */
UPDATE nested_category SET rgt = rgt + @diff WHERE rgt BETWEEN @cat_a_lft AND @cat_a_rgt;
UPDATE nested_category SET lft = lft + @diff WHERE lft BETWEEN @cat_a_lft AND @cat_a_rgt;
/* Close the gap created when we moved cat_a. */
UPDATE nested_category SET rgt = rgt - @cat_a_width WHERE rgt >= @cat_a_lft;
UPDATE nested_category SET lft = lft - @cat_a_width WHERE lft >= @cat_a_lft;
COMMIT;
END$$
DROP PROCEDURE IF EXISTS `ADD_SIBLING`$$
CREATE PROCEDURE `ADD_SIBLING`(IN `$container` VARCHAR(20), IN `$name` VARCHAR(20))
BEGIN
START TRANSACTION;
SELECT @myRight := rgt FROM nested_category WHERE name = $container;
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;
INSERT INTO nested_category(name, lft, rgt) VALUES($name, @myRight + 1, @myRight + 2);
COMMIT;
END$$
DROP PROCEDURE IF EXISTS `ADD_CHILD`$$
CREATE PROCEDURE `ADD_CHILD`(IN `$container` VARCHAR(20), IN `$name` VARCHAR(20))
BEGIN
START TRANSACTION;
SELECT @myLeft := lft FROM nested_category WHERE name = $container;
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myLeft;
UPDATE nested_category SET lft = lft + 2 WHERE lft > @myLeft;
INSERT INTO nested_category(name, lft, rgt) VALUES($name, @myLeft + 1, @myLeft + 2);
COMMIT;
END$$
DROP PROCEDURE IF EXISTS `REMOVE_NODE`$$
CREATE PROCEDURE `REMOVE_NODE`(IN `$name` VARCHAR(20))
BEGIN
START TRANSACTION;
SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = $name;
DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;
UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight;
COMMIT;
END$$
DROP PROCEDURE IF EXISTS `REMOVE_NODE_ONLY`$$
CREATE PROCEDURE `REMOVE_NODE_ONLY`(IN `$name` VARCHAR(20))
BEGIN
START TRANSACTION;
SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = $name;
DELETE FROM nested_category WHERE lft = @myLeft;
UPDATE nested_category SET rgt = rgt - 1, lft = lft - 1 WHERE lft BETWEEN @myLeft AND @myRight;
UPDATE nested_category SET rgt = rgt - 2 WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft - 2 WHERE lft > @myRight;
COMMIT;
END$$
DELIMITER ;
Ten post edytował everth 7.08.2010, 00:08:54