Question

Je besoin d'une requête MySQL qui déplace un nœud et tous ses enfants dans un ensemble imbriqué. J'ai trouvé ce site , mais cette fonction semble tellement illogique - il n'y a pas universeid ou treeid dans un modèle de jeu imbriqué et le code lui-même est juste plus long que ce qui semble nécessaire. La seule colonne supplémentaire que j'ai dans la table est parent.

Je ne pouvais pas supprimer et ajouter à nouveau le nœud car il perd son identité.

Était-ce utile?

La solution

Je vois que ce sujet est assez vieux, mais de toute façon c'est toujours sans réponse. Je suis arrivé ici de Google, et n'a trouvé aucune réponse directe à cette question.

Alors, après un peu de recherche, j'ai trouvé une solution assez facile.

Tout ce que nous devons va déplacer notre nœud est: noeud positions à gauche et à droite, nouvelle position droite nœud parent. Le nœud à la nouvelle position peut alors être déplacé en quatre étapes faciles:

  1. Modifier les positions de noeud et tous ses nœuds sous en valeurs négatives, qui sont égales à celles en vigueur par module.
  2. Déplacer toutes les positions "vers le haut", plus que pos_right du noeud courant.
  3. Déplacer toutes les positions "vers le bas", qui sont plus que pos_right du nouveau nœud parent.
  4. Modifier les positions de noeud courant et tous ses sous-noeuds, de sorte qu'il est maintenant exactement « après » (ou « vers le bas ») du nouveau nœud parent.

C'est la théorie, maintenant - cette réalisation de l'algorithme dans MySQL (par exemple en utilisant PHP):

-- step 0: Initialize parameters.
SELECT
    @node_id := 1, --put there id of moving node 
    @node_pos_left := 0, --put there left position of moving node
    @node_pos_right := 1, --put there right position of moving node
    @parent_id := 2, --put there id of new parent node (there moving node should be moved)

    @parent_pos_right := 4; --put there right position of new parent node (there moving node should be moved)
SELECT
    @node_size := @node_pos_right - @node_pos_left + 1; -- 'size' of moving node (including all it's sub nodes)

-- step 1: temporary "remove" moving node

UPDATE `list_items`
SET `pos_left` = 0-(`pos_left`), `pos_right` = 0-(`pos_right`)
WHERE `pos_left` >= @node_pos_left AND `pos_right` <= @node_pos_right;

-- step 2: decrease left and/or right position values of currently 'lower' items (and parents)

UPDATE `list_items`
SET `pos_left` = `pos_left` - @node_size
WHERE `pos_left` > @node_pos_right;
UPDATE `list_items`
SET `pos_right` = `pos_right` - @node_size
WHERE `pos_right` > @node_pos_right;

-- step 3: increase left and/or right position values of future 'lower' items (and parents)

UPDATE `list_items`
SET `pos_left` = `pos_left` + @node_size
WHERE `pos_left` >= IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_size, @parent_pos_right);
UPDATE `list_items`
SET `pos_right` = `pos_right` + @node_size
WHERE `pos_right` >= IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_size, @parent_pos_right);

-- step 4: move node (ant it's subnodes) and update it's parent item id

UPDATE `list_items`
SET
    `pos_left` = 0-(`pos_left`)+IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_pos_right - 1, @parent_pos_right - @node_pos_right - 1 + @node_size),
    `pos_right` = 0-(`pos_right`)+IF(@parent_pos_right > @node_pos_right, @parent_pos_right - @node_pos_right - 1, @parent_pos_right - @node_pos_right - 1 + @node_size)
WHERE `pos_left` <= 0-@node_pos_left AND `pos_right` >= 0-@node_pos_right;
UPDATE `list_items`
SET `parent_item_id` = @parent_id
WHERE `item_id` = @node_id;

S'il vous plaît méfiez-vous - il peut toujours y avoir des erreurs de syntaxe dans le code SQL, parce que je l'utilise en fait cet algorithme en PHP comme ceci:

$iItemId = 1;
$iItemPosLeft = 0;
$iItemPosRight = 1;
$iParentId = 2;
$iParentPosRight = 4;
$iSize = $iPosRight - $iPosLeft + 1;
$sql = array(

    // step 1: temporary "remove" moving node

    'UPDATE `list_items`
    SET `pos_left` = 0-(`pos_left`), `pos_right` = 0-(`pos_right`)
    WHERE `pos_left` >= "'.$iItemPosLeft.'" AND `pos_right` <= "'.$iItemPosRight.'"',

    // step 2: decrease left and/or right position values of currently 'lower' items (and parents)

    'UPDATE `list_items`
    SET `pos_left` = `pos_left` - '.$iSize.'
    WHERE `pos_left` > "'.$iItemPosRight.'"',
    'UPDATE `list_items`
    SET `pos_right` = `pos_right` - '.$iSize.'
    WHERE `pos_right` > "'.$iItemPosRight.'"',

    // step 3: increase left and/or right position values of future 'lower' items (and parents)

    'UPDATE `list_items`
    SET `pos_left` = `pos_left` + '.$iSize.'
    WHERE `pos_left` >= "'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iSize : $iParentPosRight).'"',
    'UPDATE `list_items`
    SET `pos_right` = `pos_right` + '.$iSize.'
    WHERE `pos_right` >= "'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iSize : $iParentPosRight).'"',

    // step 4: move node (ant it's subnodes) and update it's parent item id

    'UPDATE `list_items`
    SET
        `pos_left` = 0-(`pos_left`)+'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iItemPosRight - 1 : $iParentPosRight - $iItemPosRight - 1 + $iSize).',
        `pos_right` = 0-(`pos_right`)+'.($iParentPosRight > $iItemPosRight ? $iParentPosRight - $iItemPosRight - 1 : $iParentPosRight - $iItemPosRight - 1 + $iSize).'
    WHERE `pos_left` <= "'.(0-$iItemPosLeft).'" AND i.`pos_right` >= "'.(0-$iItemPosRight).'"',
    'UPDATE `list_items`
    SET `parent_item_id` = "'.$iParentItemId.'"
    WHERE `item_id`="'.$iItemId.'"'
);

foreach($sql as $sqlQuery){
    mysql_query($sqlQuery);
}

S'il vous plaît noter également, que le code peut être optimisé, mais je vais le laisser comme ça pour une meilleure lisibilité. Voir également le verrouillage de table si vous utilisez des ensembles imbriqués dans les systèmes multi-utilisateurs.

L'espoir que mon message vous aidera à tout le monde, qui recherche une solution après moi. Les commentaires et corrections sont également les bienvenus.

Autres conseils

Voici une solution qui vous permet de déplacer un nœud à une position dans l'arbre, soit en tant que frères et soeurs ou un enfant avec juste un seul paramètre d'entrée -. La nouvelle position gauche (newlpos) du noeud

Fondamentalement, il y a trois étapes:

  • Créer un nouvel espace pour la sous-arborescence.
  • Déplacer la sous-arborescence dans cet espace.
  • Supprimer l'ancien espace laissé vacant par le sous-arbre.

il semble en pseudo-sql, comme ceci:

//
 *  -- create new space for subtree
 *  UPDATE tags SET lpos = lpos + :width WHERE lpos >= :newlpos
 *  UPDATE tags SET rpos = rpos + :width WHERE rpos >= :newlpos
 * 
 *  -- move subtree into new space
 *  UPDATE tags SET lpos = lpos + :distance, rpos = rpos + :distance
 *           WHERE lpos >= :tmppos AND rpos < :tmppos + :width
 * 
 *  -- remove old space vacated by subtree
 *  UPDATE tags SET lpos = lpos - :width WHERE lpos > :oldrpos
 *  UPDATE tags SET rpos = rpos - :width WHERE rpos > :oldrpos
 */

La: variable est la distance entre les positions nouvelles et anciennes, la: largeur est la taille du sous-arbre, et: tmppos est utilisé pour garder une trace du sous-arbre étant déplacé au cours des mises à jour. Ces variables sont définies comme suit:

// calculate position adjustment variables
int width = node.getRpos() - node.getLpos() + 1;
int distance = newlpos - node.getLpos();
int tmppos = node.getLpos();

// backwards movement must account for new space
if (distance < 0) {
    distance -= width;
    tmppos += width;
}

Pour un exemple de code complet, voir mon blog à

http: // www.ninthavenue.com.au/how-to-move-a-node-in-nested-sets-with-sql

Si vous aimez cette solution, s'il vous plaît vous-voix.

Je sais que c'est une vieille question, mais je l'ai juste utilisé la réponse moi-même, mais pour SQL Server. Si quelqu'un veut, voici le code pour un serveur SQL stocké Proc en fonction de la réponse acceptée.

CREATE PROCEDURE [dbo].[Item_Move] 
    @id uniqueidentifier, 
    @destinationId uniqueidentifier
AS
BEGIN

    SET NOCOUNT ON;

    declare @moverLeft int,
            @moverRight int,
            @destinationRight int,
            @node_size int

    -- step 0: Initialize parameters.
    SELECT 
        @moverLeft = leftExtent, 
        @moverRight = rightExtent 
    FROM 
        Item 
    WHERE 
        id = @id

    SELECT 
        @destinationRight = rightExtent 
    FROM 
        Item 
    WHERE 
        id = @destinationId

    SELECT
        @node_size = @moverRight - @moverLeft + 1; -- 'size' of moving node (including all it's sub nodes)

    -- step 1: temporary "remove" moving node
    UPDATE Item
    SET leftExtent = 0-(leftExtent), rightExtent = 0-(rightExtent), updatedDate = GETDATE()
    WHERE leftExtent >= @moverLeft AND rightExtent <= @moverRight;

    -- step 2: decrease left and/or right position values of currently 'lower' items (and parents)
    UPDATE Item
    SET leftExtent = leftExtent - @node_size, updatedDate = GETDATE()
    WHERE leftExtent > @moverRight;
    UPDATE Item
    SET rightExtent = rightExtent - @node_size, updatedDate = GETDATE()
    WHERE rightExtent > @moverRight;

    -- step 3: increase left and/or right position values of future 'lower' items (and parents)
    UPDATE Item
    SET leftExtent = leftExtent + @node_size, updatedDate = GETDATE()
    WHERE leftExtent >= CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @node_size ELSE @destinationRight END;
    UPDATE Item
    SET rightExtent = rightExtent + @node_size, updatedDate = GETDATE()
    WHERE rightExtent >= CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @node_size ELSE @destinationRight END;

    -- step 4: move node (and it's subnodes) and update it's parent item id
    UPDATE Item
    SET
        leftExtent = 0-(leftExtent) + CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @moverRight - 1 ELSE @destinationRight - @moverRight - 1 + @node_size END,
        rightExtent = 0-(rightExtent) + CASE WHEN @destinationRight > @moverRight THEN @destinationRight - @moverRight - 1 ELSE @destinationRight - @moverRight - 1 + @node_size END, 
        updatedDate = GETDATE()
    WHERE leftExtent <= 0-@moverLeft AND rightExtent >= 0-@moverRight;
    UPDATE Item
    SET parentId = @destinationId, updatedDate = GETDATE()
    WHERE id = @id;


END

Déplacement est autour de sous-arbres très coûteux et complexe dans la conception ensembles imbriqués.

Vous devriez envisager un design différent pour représenter les arbres.

Par exemple, si vous utilisez la conception de Énumération Path, vous stockez la liste des ancêtres directs de chaque noeud comme une chaîne concaténée.

id path
 1  1/
 2  1/2/
 3  1/3/
 4  1/3/4/
 5  1/3/5/

Ensuite, le déplacement d'un sous-arbre (dit noeud 3 se déplace d'être un enfant du nœud 2):

UPDATE Tree t
 JOIN Tree node2 ON (node2.id = 2)
 JOIN Tree node3 ON (node3.id = 3)
SET t.path = CONCAT(node2.path, REPLACE(t.path, node3.path, node2.path))
WHERE t.path LIKE CONCAT(node3.path, '%');

Voir l'article dans mon blog pour le stockage et l'utilisation des données hiérarchiques dans MySQL:

Pour déplacer toute une branche dans une telle table, vous aurez juste besoin de mettre à jour le parent de la racine (une seule ligne)

Vous devez créer une fonction:

CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INT
NOT DETERMINISTIC
READS SQL DATA
BEGIN
        DECLARE _id INT;
        DECLARE _parent INT;
        DECLARE _next INT;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;

        SET _parent = @id;
        SET _id = -1;

        IF @id IS NULL THEN
                RETURN NULL;
        END IF;

        LOOP
                SELECT  MIN(id)
                INTO    @id
                FROM    t_hierarchy
                WHERE   parent = _parent
                        AND id > _id;
                IF @id IS NOT NULL OR _parent = @start_with THEN
                        SET @level = @level + 1;
                        RETURN @id;
                END IF;
                SET @level := @level - 1;
                SELECT  id, parent
                INTO    _id, _parent
                FROM    t_hierarchy
                WHERE   id = _parent;
        END LOOP;
END

et l'utiliser dans une requête:

SELECT  CONCAT(REPEAT('    ', level - 1), CAST(hi.id AS CHAR)) AS treeitem, parent, level
FROM    (
        SELECT  hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level
        FROM    (
                SELECT  @start_with := 0,
                        @id := @start_with,
                        @level := 0
                ) vars, t_hierarchy
        WHERE   @id IS NOT NULL
        ) ho
JOIN    t_hierarchy hi
ON      hi.id = ho.id

I ai une procédure stockée qui se déplace d'un noeud dans un ensemble imbriqué à un nouveau nœud parent. J'utilise une table appelée « catégorie » dans une base de données MySQL / InnoDB appelé « somedb ». Bien sûr, si la destination est une sous-catégorie de la catégorie que vous souhaitez déplacer cette procédure visserez les choses, alors assurez-vous que vous n'êtes pas essayer d'intégrer un noeud à l'intérieur de lui-même. Je laisse comme un exercice au lecteur de faire cette procédure en toute sécurité pour ce cas.

CREATE PROCEDURE `somedb`.`moveCatParent` (IN cat_a VARCHAR(45), IN cat_b VARCHAR(45))
BEGIN
    START TRANSACTION;

    /* cat_b.lft + 1 is the destination. */
    SELECT @destination := (lft + 1)
    FROM category
    WHERE name = cat_b;

    SELECT @cat_a_width := ((rgt - lft) + 1)
    FROM category
    WHERE name = cat_a;

    /* Rip this table a new cat_a sized hole inside cat_b. */  
    UPDATE category SET rgt = rgt + @cat_a_width WHERE rgt >= @destination;
    UPDATE category SET lft = lft + @cat_a_width WHERE lft >= @destination;

    SELECT @cat_a_lft := lft, @cat_a_rgt := rgt
    FROM category
    WHERE name = cat_a;

    SELECT @diff := @destination - @cat_a_lft;

    /* Move cat_a and all inhabitants to new hole */  
    UPDATE category SET rgt = rgt + @diff WHERE rgt BETWEEN @cat_a_lft AND @cat_a_rgt;
    UPDATE 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 category SET rgt = rgt - @cat_a_width WHERE rgt >= @cat_a_lft;
    UPDATE category SET lft = lft - @cat_a_width WHERE lft >= @cat_a_lft;

    COMMIT;
END

Je crois que deux colonnes supplémentaires pour stocker le droit de nœud d'origine et les valeurs de gauche (et tous les sous-noeuds ultérieurs) l'algorithme peut être simplifié. Je travaille avec les exemples crayon et du papier, donc si vous trouvez des trous dans l'algorithme s'il vous plaît laissez-moi savoir.

Le nœud cible (le nouveau parent du nœud que vous déplacez) est TNODE. A gauche de la valeur cible est la valeur Noeud tNode.L et à droite est tNode.R. De même, le nœud que vous déplacez est mnode et les valeurs de gauche et de droite pour mnode sont mNode.L et mNode.R. Les deux colonnes supplémentaires sont mNode.SL et mNode.SR

Donc dans l'ensemble, nous avons 4 colonnes pour la manipulation R, L, SL et SR


Etape 1

Calcul

delta1 = (mNode.R - mNode.L) + 1 

Etape 2

Enregistrer l'original mnode L et R en colonnes SL et SR

- For All L between mNode.L and mNode.R 
   mNode.SL = mNode.L ; mNode.L = 0 ;
 - For All R between mNode.L and mNode.R 
   mNode.SR = mNode.R ; mNode.R = 0 ;

Etape 3

Do For all Nodes
IF L > mNode.SR 
   L = L + delta1
IF R > mNode.SR
   R = R + delta1

Maintenant, le mnode est détaché de l'arbre et l'arbre est ajustée sans mnode.

Step4

Calcul

delta2 = (tNode.R - mNode.SL)

Step5

Do for all Nodes
  IF L >= tNode.R
    L = L + delta1
  IF R >= tNode.R
    R = R + delta1

Maintenant, nous avons ajusté l'arbre (et le noeud cible) d'accepter le nombre de noeuds qui ont été supprimés.

Step6

Joindre mnode à TNODE et réinitialiser les valeurs de colonne SL / SR

Do for all Nodes
 IF SL between mNode.SL and mNode.SR
    L = mNode.SL + delta2 ; mNode.SL = 0  ;
 IF SR between mNode.SL and mNode.SR
    R = mNode.SR + delta2 ; mNode.SR = 0 ;

Après toutes ces étapes, nous aurions dû mnode sous le TNODE.

Merci pour l'idée de transformer le LFT et rgt à leurs homologues négatifs. J'ai posté une approche plus générale de cette ici: Déplacer nœud dans l'arbre Définit Nested .

La fonction queryBatch () entoure la requête d'une transaction.

Il est tout à fait simple, d'abord définir une procédure stockée:

   CREATE DEFINER=`root`@`localhost` PROCEDURE `move_item`(
        IN itemId BIGINT, IN kind SMALLINT, 
        IN newSiblingId BIGINT UNSIGNED, IN newSiblingKind SMALLINT, IN newParentId BIGINT UNSIGNED,
        IN jobId BIGINT UNSIGNED, IN companyId BIGINT UNSIGNED,
        OUT outSucess SMALLINT UNSIGNED)
proc_label:BEGIN

Ensuite, il faut des variables locales:

DECLARE oldLeft, oldRight, newLeft, newRight, itemWidth, moveBy INT UNSIGNED DEFAULT 0; 
set outSucess =0;

Maintenant obtenir notre vieille gauche et à droite et obtenir la largeur

SELECT `LFT`, `RGT` into oldLeft, oldRight from `nodes` where `ID`=itemId LIMIT 1;
SET itemWidth = oldRight - oldLeft + 1;

Maintenant les prendre « de l'arbre » en multipliant par -1

UPDATE `nodes` SET `RGT`=`RGT`* -1, `LFT`=`LFT`* -1 WHERE ``LFT` BETWEEN oldLeft and oldRight;

La partie suivante n'est pas nécessaire que l'arbre fonctionnera sans, mais il est propre; fermer l'ancien espace:

-- Update right
UPDATE `nodes` SET `RGT` = `RGT` - itemWidth WHERE `RGT` > oldRight;
-- Update left
UPDATE `nodes` SET `LFT` = `LFT` - itemWidth WHERE `LFT` > oldRight;

Maintenant, trouver le nouvel emplacement:

SELECT (`RGT`+1) into newLeft from `nodes`  where `ID`=newSiblingId LIMIT 1;

-- No sibling, so make it last in parent
IF (newLeft = 0) AND (newParentId != 0) THEN
  SELECT `RGT` into newLeft from `nodes` WHERE `ID`=newParentId LIMIT 1;
END IF;

 -- If no previous sibling or parent, set to first item in tree
IF (newLeft=0) OR (newLeft=NULL) THEN SET newLeft=1;
END IF;

Maintenant, faites un peu d'espace:

 -- Update right
UPDATE `nodes` SET `RGT` = `RGT` + itemWidth WHERE `RGT` >= newLeft;
-- Update left
UPDATE `nodes` SET `LFT` = `LFT` + itemWidth WHERE `LFT` >= newLeft;

Enfin déplacer les noeuds où déplacé de l'arbre par retour dans * -1, et pendant que vous y êtes, les déplacer à l'emplacement correct ainsi:

SET moveBy = OldLeft - NewLeft;
UPDATE `nodes` SET `RGT`=(`RGT`* -1)-moveBy, `LFT`=(`LFT`* -1)-moveBy WHERE `LFT` < 0;
set outSucess =1;

Non testé, collé et ajusté et simplifié d'une routine de travail.

Je sais que ce post est vieux, mais im affichant cette solution pour tout le monde qui se ici pour voir un solution.I trouvé ce @ sedna-soft.de. Je l'ai testé id et fonctionne parfaitement

 -- moves a subtree before the specified position
 -- if the position is the rgt of a node, the subtree will be its last child
 -- if the position is the lft of a node, the subtree will be inserted before
 -- @param l the lft of the subtree to move
 -- @param r the rgt of the subtree to move
 -- @param p the position to move the subtree before




 SET @r: , @l: , @p: 

 update tree
 set
 lft = lft + if (@p > @r,
    if (@r < lft and lft < @p,
        @l - @r - 1,
        if (@l <= lft and lft < @r,
            @p - @r - 1,
            0
        )
    ),
    if (@p <= lft and lft < @l,
        @r - @l + 1,
        if (@l <= lft and lft < @r,
            @p - @l,
            0
        )
    )
),
rgt = rgt + if (@p > @r,
    if (@r < rgt and rgt < @p,
        @l - @r - 1,
        if (@l < rgt and rgt <= @r,
            @p - @r - 1,
            0
        )
    ),
    if (@p <= rgt and rgt < @l,
        @r - @l + 1,
        if (@l < rgt and rgt <= @r,
            @p - @l,
            0
        )
    )
        )
  where @r < @p or @p < @l; 
# Get Left and Right offsets of both source node (Drag Node) and target node (Drop off Node).
SELECT lft,rgt INTO @sourceNodeLft,@sourceNodeRgt FROM treetest WHERE id=_sourceNodeId;
SELECT lft,rgt INTO @targetNodeLft,@targetNodeRgt FROM treetest WHERE id=_targetNodeId;

# Determine node order direction
SET @direction := IF(@targetNodeLft<@sourceNodeLft,'UP','DOWN'); 

# Determine with of source node (Drag Node)
SET @width := @sourceNodeRgt - @sourceNodeLft + 1;

# Mark all displaced nodes with negative lft and rgt
UPDATE treetest SET lft = 0-lft, rgt = 0-rgt 
                                WHERE lft >= @targetNodeLft AND rgt <= @targetNodeRgt;
UPDATE treetest SET lft = 0-lft, rgt = 0-rgt 
                                WHERE lft >= @sourceNodeLft AND rgt <= @sourceNodeRgt;


# Update left and right offsets of inner nodes between source (Drag Node)and target (Drop off) node
UPDATE treetest SET lft =   (lft + IF(@direction = 'UP',@width,0-@width)),
                                    rgt = (rgt + IF(@direction = 'UP',@width,0-@width))
                                WHERE lft > IF(@direction = 'UP', @targetNodeLft, @sourceNodeLft)
                                            AND rgt < IF(@direction = 'UP', @sourceNodeLft, @targetNodeLft);


# Update source (Drag) Node and its children offsets  
SET @sourceOffset := IF(@direction = 'UP',@targetNodeLft - @sourceNodeLft, @targetNodeRgt - @width - @sourceNodeLft+1);
UPDATE treetest SET lft = 0 - lft + @sourceOffset, 
                                        rgt = 0 - rgt + @sourceOffset
                                WHERE (0-lft) >= @sourceNodeLft AND (0-rgt) <= @sourceNodeRgt;

# Update target (Drop off) node and its children offsets
SET @targetOffset := IF(@direction = 'UP', 0 - @width,@width);
UPDATE treetest SET lft = 0 - (lft + @targetOffset),
                                        rgt = 0 - (rgt + @targetOffset)
                                WHERE (0-lft) >= @targetNodeLft AND (0-rgt) <= @targetNodeRgt;


Il y a beaucoup de réponses déjà, mais je me sens comme le mien peut être utile pour quelqu'un. Sur la base de réponse de Roger Keays (! Merci beaucoup), j'ai écrit des procédures stockées pour la base de données mySQL:

-- to move target before specified node
CREATE DEFINER=`root`@`%` PROCEDURE `move_before`(IN target_id int, before_id int)
BEGIN
    SELECT @new_pos := lft FROM dirs WHERE  id = before_id; 
    CALL  move(target_id, @new_pos);
END

-- to move target after specified node
CREATE DEFINER=`root`@`%` PROCEDURE `move_after`(IN target_id int, after_id int)
BEGIN
    SELECT @new_pos := rgt + 1 FROM dirs WHERE  id = after_id;
    CALL  move(target_id, @new_pos);
END

-- to move target to the specified node
CREATE DEFINER=`root`@`%` PROCEDURE `move_in`(IN target_id int, parent_id int)
BEGIN
    SELECT @new_pos := rgt FROM dirs WHERE  id = parent_id;
    CALL  move(target_id, @new_pos);
END

--main procedure to move target before position 
CREATE DEFINER=`root`@`%` PROCEDURE `move`(in target_id int, in  new_pos int)
BEGIN

    SELECT @oldlft :=  lft, @oldrgt :=  rgt 
    FROM dirs 
    WHERE target_id =  id;

    SET @width := @oldrgt - @oldlft +1;
    SET @distance :=  new_pos - @oldlft;
    SET @tmppos := @oldlft;

    IF (@distance <0)
    THEN
        SELECT @distance := @distance - @width;
        SELECT @tmppos := @tmppos + @width;
    END IF;

    -- create new space for subtree
    UPDATE dirs SET lft = lft + @width WHERE lft >=  new_pos;
    UPDATE dirs SET rgt = rgt + @width WHERE rgt >=  new_pos;

    -- move subtree into new space
    UPDATE dirs SET lft = lft + @distance, rgt = rgt + @distance
        WHERE lft >= @tmppos AND rgt < @tmppos + @width;

    -- remove old space vacated by subtree
    UPDATE dirs SET lft = lft - @width WHERE lft > @oldrgt;
    UPDATE dirs SET rgt = rgt - @width WHERE rgt > @oldrgt;

END

$ ligne est un tableau qui représente la ligne I ai à se déplacer; il doit être comme ceci:

Array ( [lft] => 5 [rgt] => 10 [width] => 6 ) 

$ row2 est un tableau qui représente le nœud de destination;

Array ( [id] => 5 [lft] => 2 [rgt] => 17 [width] => 16 ) 

...

mysql_query("UPDATE entryCategory SET rgt = rgt + %d - %d, lft = lft + %d - %d WHERE rgt <= %d and lft >= %d;",$row2["rgt"],$row["lft"],$row2["rgt"],$row["lft"],$row["rgt"],$row["lft"]);
mysql_query("UPDATE entryCategory SET rgt = rgt + %d WHERE id=%d;",$row["width"],$row2["id"]);
mysql_query("UPDATE entryCategory SET rgt = rgt - %d, lft = lft - %d  WHERE rgt > %d and lft > %d;",$row["width"],$row["width"],$row["rgt"],$row["rgt"]);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top