Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> pytanie o nested set
wiewiorek
post
Post #1





Grupa: Zarejestrowani
Postów: 247
Pomógł: 11
Dołączył: 5.09.2009

Ostrzeżenie: (0%)
-----


Jak mamy w bazie danych tabelę z kolumnami:
id | id_parent | order
To dodając nowy element użytkownik wybiera z select listy rodzica oraz z drugiej select listy liczbę reprezentującą wagę/kolejność dodawanego elementu w stosunku do innych na tym samym poziomie.

A jak mamy w bazie danych tabelę ze strukturą charakterystyczną dla nested set:
id | left | right
To użytkownik dodając nowy element wybiera z select listy rodzica, ale w jaki sposób może ustalić wagę/kolejność nowo dodawanego elementu w stosunku do innych na tym samym poziomie ? Nie bardzo wiem jak umożliwić użytkownikom ustalenie kolejności.


Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
everth
post
Post #2





Grupa: Zarejestrowani
Postów: 782
Pomógł: 153
Dołączył: 21.07.2010

Ostrzeżenie: (0%)
-----


@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:
  1. CALL MOVE_BRANCH('NAZWA','DOKĄD'); -- przenosi gałąź NAZWA do kontenera DOKĄD
  2. CALL ADD_SIBLING('OBOK','NAZWA'); -- tworzy nowy węzeł "NAZWA" obok węzła OBOK
  3. CALL ADD_CHILD('RODZIC','NAZWA'); -- dodaje węzeł NAZWA do kontenera RODZIC
  4. CALL REMOVE_NODE('NAZWA'); -- usuwa węzeł NAZWA wraz z wszystkimi dziećmi
  5. CALL REMOVE_NODE_ONLY('NAZWA'); -- usuwa węzeł NAZWA, dzieci zostają przeniesione poziom wyżej

Templata z procedurami jest taka:
  1. DELIMITER $$
  2.  
  3. DROP PROCEDURE IF EXISTS `MOVE_BRANCH`$$
  4. CREATE PROCEDURE `MOVE_BRANCH` (IN `$FROM` VARCHAR(20), IN `$TO` VARCHAR(20))
  5. BEGIN
  6. START TRANSACTION;
  7.  
  8. /* cat_b.lft + 1 is the destination. */
  9. SELECT @destination := (lft + 1) FROM nested_category WHERE name = `$TO`;
  10.  
  11. SELECT @cat_a_width := ((rgt - lft) + 1) FROM nested_category WHERE name = `$FROM`;
  12.  
  13. /* Rip this table a new cat_a sized hole inside cat_b. */
  14. UPDATE nested_category SET rgt = rgt + @cat_a_width WHERE rgt >= @destination;
  15. UPDATE nested_category SET lft = lft + @cat_a_width WHERE lft >= @destination;
  16.  
  17. SELECT @cat_a_lft := lft, @cat_a_rgt := rgt FROM nested_category WHERE name = `$FROM`;
  18.  
  19. SELECT @diff := @destination - @cat_a_lft;
  20.  
  21. /* Move cat_a and all inhabitants to new hole */
  22. UPDATE nested_category SET rgt = rgt + @diff WHERE rgt BETWEEN @cat_a_lft AND @cat_a_rgt;
  23. UPDATE nested_category SET lft = lft + @diff WHERE lft BETWEEN @cat_a_lft AND @cat_a_rgt;
  24.  
  25. /* Close the gap created when we moved cat_a. */
  26. UPDATE nested_category SET rgt = rgt - @cat_a_width WHERE rgt >= @cat_a_lft;
  27. UPDATE nested_category SET lft = lft - @cat_a_width WHERE lft >= @cat_a_lft;
  28.  
  29. COMMIT;
  30. END$$
  31.  
  32. DROP PROCEDURE IF EXISTS `ADD_SIBLING`$$
  33. CREATE PROCEDURE `ADD_SIBLING`(IN `$container` VARCHAR(20), IN `$name` VARCHAR(20))
  34. BEGIN
  35. START TRANSACTION;
  36. SELECT @myRight := rgt FROM nested_category WHERE name = $container;
  37. UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight;
  38. UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;
  39. INSERT INTO nested_category(name, lft, rgt) VALUES($name, @myRight + 1, @myRight + 2);
  40. COMMIT;
  41. END$$
  42.  
  43. DROP PROCEDURE IF EXISTS `ADD_CHILD`$$
  44. CREATE PROCEDURE `ADD_CHILD`(IN `$container` VARCHAR(20), IN `$name` VARCHAR(20))
  45. BEGIN
  46. START TRANSACTION;
  47. SELECT @myLeft := lft FROM nested_category WHERE name = $container;
  48. UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myLeft;
  49. UPDATE nested_category SET lft = lft + 2 WHERE lft > @myLeft;
  50. INSERT INTO nested_category(name, lft, rgt) VALUES($name, @myLeft + 1, @myLeft + 2);
  51. COMMIT;
  52. END$$
  53.  
  54. DROP PROCEDURE IF EXISTS `REMOVE_NODE`$$
  55. CREATE PROCEDURE `REMOVE_NODE`(IN `$name` VARCHAR(20))
  56. BEGIN
  57. START TRANSACTION;
  58. SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = $name;
  59. DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;
  60. UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
  61. UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight;
  62. COMMIT;
  63. END$$
  64.  
  65. DROP PROCEDURE IF EXISTS `REMOVE_NODE_ONLY`$$
  66. CREATE PROCEDURE `REMOVE_NODE_ONLY`(IN `$name` VARCHAR(20))
  67. BEGIN
  68. START TRANSACTION;
  69. SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = $name;
  70. DELETE FROM nested_category WHERE lft = @myLeft;
  71. UPDATE nested_category SET rgt = rgt - 1, lft = lft - 1 WHERE lft BETWEEN @myLeft AND @myRight;
  72. UPDATE nested_category SET rgt = rgt - 2 WHERE rgt > @myRight;
  73. UPDATE nested_category SET lft = lft - 2 WHERE lft > @myRight;
  74. COMMIT;
  75. END$$
  76.  
  77. DELIMITER ;


Ten post edytował everth 7.08.2010, 00:08:54
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 12.10.2025 - 20:50