Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Pindahkan simpul dalam kumpulan bersarang

Saya mengerti, bahwa topik ini sudah cukup lama, tetapi masih belum terjawab. Saya sampai di sini dari Google, dan tidak menemukan jawaban langsung untuk pertanyaan ini.

Jadi, setelah sedikit riset saya menemukan solusi yang cukup mudah.

Semuanya, apa yang kita perlukan untuk memindahkan node kita adalah:posisi kiri dan kanan node, posisi kanan node induk baru. Node ke posisi baru kemudian dapat dipindahkan dalam empat langkah mudah:

  1. Ubah posisi node dan semua sub nodenya menjadi nilai negatif, yang sama dengan nilai saat ini berdasarkan modul.
  2. Pindahkan semua posisi "naik", yang lebih, pos_kanan dari simpul saat ini.
  3. Pindahkan semua posisi "ke bawah", yang lebih, pos_right dari simpul induk baru.
  4. Ubah posisi node saat ini dan semua subnodenya, sehingga posisinya sekarang persis "setelah" (atau "turun") dari node induk baru.

Itu teori, sekarang - realisasi algoritma ini di MySQL (contoh menggunakan 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;

Harap berhati-hati - mungkin masih ada beberapa kesalahan sintaks dalam kode SQL, karena saya sebenarnya menggunakan algoritma ini di PHP seperti ini:

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

Harap perhatikan juga, kode itu mungkin dioptimalkan, tetapi saya akan membiarkannya seperti itu agar lebih mudah dibaca. Pertimbangkan juga penguncian tabel jika Anda menggunakan kumpulan bersarang dalam sistem multi-pengguna.

Semoga pesan saya akan membantu siapa saja, yang akan mencari solusi setelah saya. Setiap komentar dan koreksi juga diterima.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Operator MINUS di MySQL?

  2. Bisakah saya menggunakan lapisan basis data Laravel secara mandiri?

  3. Menggunakan Java untuk membuat koneksi aman ke MySQL Amazon RDS (SSL/TLS)

  4. hasilkan hari dari rentang tanggal

  5. Ubah nilai kolom yang dipilih ke baris lain menggunakan pilih dengan id yang sama part2