Les précédents articles[1][2] sur le stockage et la manipulation des hiérarchies dans MySQL sont loin d'être complets. J'y apporte donc un complément avec 2 nouvelles requêtes de manipulations.
On conserve la même table et les même données que dans les articles précédents afin de rester cohérent.

Déplacer un élément

Dans l'article Un peu d'ordre dans la hiérarchie, nous avons déjà abordé le déplacement d'un élément mais juste vers un autre élément de la hiérarchie. Cette fois ci, nous allons aborder le déplacement d'un élément à la racine, c'est à dire qu'il n'aura plus de parent. Nous allons donc déplacer l'élément B vers la racine. Pour cela, il suffit de lancer ces quelques requêtes :

  1. /* Verrouillage en écriture de la table*/
  2. LOCK TABLE tree WRITE;
  3.  
  4. /* Récupération des informations de l'élément à déplacer */
  5. SELECT @nodeLeft := lft
  6. , @nodeRight := rgt
  7. , @nodeRange := rgt - lft + 1
  8. FROM tree
  9. WHERE name = 'B';
  10.  
  11. /* Récupération des informations de déplacement de l'élément */
  12. SELECT @offsetRange := MAX(rgt) - @nodeRight
  13. FROM tree;
  14.  
  15. /* Exclusion temporaire de l'élément à déplacer */
  16. UPDATE tree
  17. SET lft = -lft
  18. , rgt = -rgt
  19. WHERE lft >= @nodeLeft
  20. AND rgt <= @nodeRight;
  21.  
  22. /* Mise à jour des bornes droites des éléments concernés */
  23. UPDATE tree
  24. SET rgt = rgt - @nodeRange
  25. WHERE rgt >= @nodeRight;
  26.  
  27. /* Mise à jour des bornes gauches des éléments concernés */
  28. UPDATE tree
  29. SET lft = lft - @nodeRange
  30. WHERE lft >= @nodeRight;
  31.  
  32. /* Repositionnement de l'élément à déplacer */
  33. UPDATE tree
  34. SET lft = -lft + @offsetRange
  35. , rgt = -rgt + @offsetRange
  36. WHERE rgt < 0;
  37.  
  38. /* Suppression des verrous */
  39. UNLOCK TABLES;

Ce qui nous donne ceci :

+-----------+------+------+----+
| NAME      | LFT  | RGT  | ID |
+-----------+------+------+----+
| A         |    1 |    8 |  1 |
| ----C     |    2 |    7 |  5 |
| --------F |    3 |    4 |  6 |
| --------G |    5 |    6 |  7 |
| B         |    9 |   14 |  2 |
| ----D     |   10 |   11 |  3 |
| ----E     |   12 |   13 |  4 |
+-----------+------+------+----+
7 rows in set (0.00 sec)

Récupérer le niveau d'un élément

Utilisons la requête suivante :

  1. SELECT COUNT(p.name) - 1 AS level
  2. FROM tree p
  3. , tree n
  4. WHERE n.lft BETWEEN p.lft AND p.rgt
  5. AND n.name = 'G'
  6. GROUP BY n.id

Ce qui nous donne ceci :

+-------+
| level |
+-------+
|     2 |
+-------+
1 row in set (0.00 sec)