これは、単一のクエリで実行できます。これにはたくさんのバリエーションがあると思いますが、これが私が使用するものです...
DECLARE
@node_id INT,
@new_parent_id INT
SELECT
@node_id = 5,
@new_parent = 1
UPDATE
yourTable
SET
parent_id = CASE WHEN yourTable.id = target_node.id THEN new_antiscendant.id
WHEN yourTable.id = descendant.id THEN target_node.parent_id
WHEN yourTable.id = new_descendant.id THEN target_node.id
END
FROM
yourTable AS target_node
LEFT JOIN
yourTable AS descendant
ON descendant.parent_id = target_node.id
LEFT JOIN
yourTable AS new_antiscendant
ON new_antiscendant.id = @new_parent_id
LEFT JOIN
yourTable AS new_descendant
ON COALESCE(new_descendant.parent_id, -1) = COALESCE(new_antiscendant.id, -1)
INNER JOIN
yourTable
ON yourTable.id IN (target_node.id, descendant.id, new_descendant.id)
WHERE
target_node.id = @node_id
これは、@ new_parent_idがNULLまたはリストの最後のレコードであっても、機能します。
MySQLは更新での自己結合を好まないため、アプローチはおそらく、新しいマッピングを取得するために一時テーブルにLEFTJOINを実行することです。次に、そのテーブルに参加して、1つのクエリで3つのレコードすべてを更新します。
INSERT INTO
yourTempTable
SELECT
yourTable.id AS node_id,
CASE WHEN yourTable.id = target_node.id THEN new_antiscendant.id
WHEN yourTable.id = descendant.id THEN target_node.parent_id
WHEN yourTable.id = new_descendant.id THEN target_node.id
END AS new_parent_id
FROM
yourTable AS target_node
LEFT JOIN
yourTable AS descendant
ON descendant.parent_id = target_node.id
LEFT JOIN
yourTable AS new_antiscendant
ON new_antiscendant.id = @new_parent_id
LEFT JOIN
yourTable AS new_descendant
ON COALESCE(new_descendant.parent_id, -1) = COALESCE(new_antiscendant.id, -1)
INNER JOIN
yourTable
ON yourTable.id IN (target_node.id, descendant.id, new_descendant.id)
WHERE
target_node.id = @node_id
UPDATE
yourTable
SET
parent_id = yourTempTable.newParentID
FROM
yourTable
INNER JOIN
yourTempTable
ON yourTempTamp.node_id = yourTable.id
(正確な構文はRDBMSによって異なります。)