CREATE TABLE tb(id int, name varchar(50), pid int, url varchar(10));
INSERT tb VALUES
(1, '根节点', null, '1111'),
(2, '项目1', 1, 'aaa'),
(3, '标准节点1', 2, 'bbb'),
(4, '标准节点2', 2, 'ccc'),
(5, '标准节点3', 4, 'ddd'),
(6, '项目2', 1, 'aaa'),
(7, '标准节点1', 6, 'bbb'),
(8, '标准节点2', 6, 'ccc'),
(9, '标准节点3', 8, 'ddd');
CREATE PROCEDURE p_copy(_id int)
BEGIN
-- 第一个 pid = 1 的所有级别的 id 列表(层次任意,不限于示例的数据)
DECLARE __all_ids text DEFAULT '$';
DECLARE __ids text;
DECLARE __id int;
SELECT id, id INTO __ids, __id FROM tb WHERE pid = 1 LIMIT 1;
WHILE __ids IS NOT NULL DO
SET __all_ids = CONCAT(__all_ids, ',', __ids);
SELECT GROUP_CONCAT(id) INTO __ids FROM tb WHERE FIND_IN_SET(pid, __ids);
END WHILE;
-- 根据 id 列表查出所有数据,并根据原来的上下级关系算出新的 id/pid
INSERT tb
SELECT
id + _id - __id as id, name,
IF(pid = 1, 1, pid + _id - __id) as pid, url
FROM tb WHERE FIND_IN_SET(id, __all_ids);
END;
call p_copy(66);
SELECT * FROM tb;
call p_copy(106);
SELECT * FROM tb;
DROP PROCEDURE IF EXISTS P_copy;
DROP TABLE IF EXISTS tb;
自古评论区出高手。