sql >> データベース >  >> RDS >> Mysql

ネストされたセットでノードを移動する

    このトピックはかなり古いものですが、とにかくまだ答えがありません。 Googleからここに来ましたが、この質問に対する直接の答えは見つかりませんでした。

    ですから、少し調べてみると、非常に簡単な解決策が見つかりました。

    すべて、ノードを移動するために必要なのは、ノードの左右の位置、新しい親ノードの右の位置です。ノードを新しい位置に移動するには、次の4つの簡単な手順を実行します。

    1. ノードとそのすべてのサブノードの位置を負の値に変更します。これは、モジュールごとの現在の値と同じです。
    2. 現在のノードのpos_rightのすべての位置を「上」に移動します。
    3. すべての位置を「下」に移動します。つまり、新しい親ノードのpos_rightに移動します。
    4. 現在のノードとそのすべてのサブノードの位置を変更して、新しい親ノードの正確に「後」(または「下」)になるようにします。

    これが理論です。MySQLでのこのアルゴリズムの実現(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` <= [email protected]_pos_left AND `pos_right` >= [email protected]_pos_right;
    UPDATE `list_items`
    SET `parent_item_id` = @parent_id
    WHERE `item_id` = @node_id;
    

    注意してください-私は実際に次のようにPHPでこのアルゴリズムを使用しているため、SQLコードにはまだいくつかの構文エラーがある可能性があります:

    $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);
    }
    

    また、コードは最適化されている可能性がありますが、読みやすくするためにそのままにしておきます。マルチユーザーシステムでネストされたセットを使用している場合は、テーブルのロックも検討してください。

    私のメッセージが、私の後に解決策を探す人に役立つことを願っています。コメントや訂正も歓迎します。



    1. 科学的記数法MySQLをオフにします

    2. phpを使用してmysqlに接続する

    3. Spring、Hibernate、Blobの遅延読み込み

    4. SQLとのタイムゾーンの調整