在数据库中处理树形结构数据时,删除操作需要考虑层级关系。常见场景包括:
CREATE TABLE tree_nodes (
id INT PRIMARY KEY,
name VARCHAR(100),
parent_id INT NULL,
FOREIGN KEY (parent_id) REFERENCES tree_nodes(id)
);
CREATE TABLE tree_nodes (
id INT PRIMARY KEY,
name VARCHAR(100),
path VARCHAR(1000) -- 如 "1/4/7" 表示路径
);
CREATE TABLE tree_nodes (
id INT PRIMARY KEY,
name VARCHAR(100),
lft INT NOT NULL,
rgt INT NOT NULL
);
CREATE TABLE tree_nodes (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE tree_paths (
ancestor INT NOT NULL,
descendant INT NOT NULL,
depth INT NOT NULL,
PRIMARY KEY (ancestor, descendant),
FOREIGN KEY (ancestor) REFERENCES tree_nodes(id),
FOREIGN KEY (descendant) REFERENCES tree_nodes(id)
);
-- MySQL 8.0+ 使用递归CTE
WITH RECURSIVE subtree AS (
SELECT id FROM tree_nodes WHERE id = :target_id
UNION ALL
SELECT t.id FROM tree_nodes t
JOIN subtree s ON t.parent_id = s.id
)
DELETE FROM tree_nodes WHERE id IN (SELECT id FROM subtree);
-- 1. 先更新子节点的parent_id为父节点的parent_id
UPDATE tree_nodes
SET parent_id = (SELECT parent_id FROM tree_nodes WHERE id = :target_id)
WHERE parent_id = :target_id;
-- 2. 再删除目标节点
DELETE FROM tree_nodes WHERE id = :target_id;
-- 1. 先删除路径关系
DELETE FROM tree_paths
WHERE descendant IN (
SELECT descendant FROM tree_paths
WHERE ancestor = :target_id
);
-- 2. 再删除节点
DELETE FROM tree_nodes
WHERE id IN (
SELECT descendant FROM tree_paths
WHERE ancestor = :target_id
);
-- 1. 找出所有直接子节点
WITH direct_children AS (
SELECT descendant FROM tree_paths
WHERE ancestor = :target_id AND depth = 1
)
-- 2. 更新路径关系
-- 将子节点连接到祖父节点
INSERT INTO tree_paths (ancestor, descendant, depth)
SELECT p.ancestor, c.descendant, p.depth + c.depth
FROM tree_paths p
JOIN tree_paths c ON p.descendant = :target_id AND c.ancestor = :target_id
WHERE p.ancestor != :target_id;
-- 3. 删除旧路径
DELETE FROM tree_paths
WHERE descendant IN (SELECT descendant FROM tree_paths WHERE ancestor = :target_id)
AND ancestor IN (SELECT ancestor FROM tree_paths WHERE descendant = :target_id AND ancestor != descendant);
-- 4. 删除目标节点
DELETE FROM tree_nodes WHERE id = :target_id;
原因:子节点引用了父节点的ID,直接删除父节点会违反外键约束。
解决方案:
FOREIGN KEY (parent_id) REFERENCES tree_nodes(id) ON DELETE CASCADE
原因:递归操作在大型树上效率低下。
解决方案:
原因:删除操作没有正确处理所有相关关系。
解决方案:
is_deleted
标志实现软删除而非物理删除-- 邻接表模型下删除子树的事务示例
BEGIN;
-- 创建临时表存储要删除的ID
CREATE TEMPORARY TABLE temp_nodes_to_delete (id INT PRIMARY KEY);
-- 递归查找所有子节点 (MySQL 8.0+)
INSERT INTO temp_nodes_to_delete
WITH RECURSIVE subtree AS (
SELECT id FROM tree_nodes WHERE id = :target_id
UNION ALL
SELECT t.id FROM tree_nodes t
JOIN subtree s ON t.parent_id = s.id
)
SELECT id FROM subtree;
-- 执行删除
DELETE FROM tree_nodes WHERE id IN (SELECT id FROM temp_nodes_to_delete);
-- 清理
DROP TEMPORARY TABLE temp_nodes_to_delete;
COMMIT;
以上提供了在不同树形结构表示方法下的删除操作实现,以及常见问题的解决方案。根据您的具体数据库结构和需求选择合适的方法。
没有搜到相关的文章