0

我有一个层次系统设置,将项目的级别和父 ID 存储在数据库中。我想弄清楚的是我将如何找到用户选择的所有子行。这是表结构的示例:

+----+---------+----------+-------+
| Id |  label  | parentid | level |
+----+---------+----------+-------+
|  1 | honda   |        0 |     1 |
|  2 | accord  |        1 |     2 |
|  3 | civic   |        1 |     2 |
|  4 | element |        1 |     2 |
|  5 | v4      |        2 |     3 |
|  6 | v6      |        2 |     3 |
+----+---------+----------+-------+

那么,如果有人删除honda,我将如何删除层次结构中的所有内容?数据库只会降到 3 级。

4

3 回答 3

8

参考,使用关系 innoDB 的递归 MySQL 查询

我昨天发布了同样的答案

更新:

以下是function基于上述链接的,但已根据您的DELETE要求量身定制

CREATE PROCEDURE `delete_relations`(`_id` INT)
BEGIN
DECLARE  delete_row_ids varchar(200);
DECLARE id, id2 varchar(200);
DECLARE rows_affected int;

SET delete_row_ids  = _id;
SET id              = _id;
SET id2             = id;

WHILE id2 IS NOT NULL DO 
    SET id = NULL;
    SELECT GROUP_CONCAT( hierarchical_data.id ), CONCAT( GROUP_CONCAT( hierarchical_data.ID ),',',delete_row_ids) INTO id, delete_row_ids FROM hierarchical_data WHERE FIND_IN_SET( parentid , id2 ) GROUP BY parentid ;
    SET id2 = id;
END WHILE;  

DELETE FROM hierarchical_data where FIND_IN_SET(hierarchical_data.id, delete_row_ids);
SELECT row_count() INTO rows_affected;

if rows_affected > 0 THEN
SELECT delete_row_ids as row_ids_deleted;
ELSE
SELECT 'NO_ROWS_DELETED';
END IF;

END//

SQLFiddle

利用

CALL delete_relations(1)

删除所有条目及其关系id = 1 honda

希望它有帮助

于 2013-04-16T17:04:24.847 回答
1

替换:id为以下要删除的根条目 id:

DELETE FROM table
WHERE
   id = :id 
   OR id IN (  
-- first level
SELECT DISTINCT id sid
FROM table
WHERE parentid = :id
-- second level
UNION
SELECT DISTINCT t2.id sid
FROM table t1
INNER JOIN table t2
ON t1.id = t2.parentid
WHERE t1.parentid = :id
-- third level
UNION
SELECT DISTINCT t3.id sid
FROM table t1
INNER JOIN table t2
ON t1.id = t2.parentid
INNER JOIN table t3
ON t2.id = t3.parentid
WHERE t1.id = :id
)

请注意,您有 3 个级别,但根节点占据其中之一,这意味着您实际上只需要选择子孙。上面的查询多了一层(第三层),所以你可以删除-- third level右括号之后的部分。

于 2013-04-16T17:13:00.403 回答
1

假设您在具有触发器的 MySQL 5 上,您可以编写一个小的删除前触发器来轻松实现此目的。我没有完全检查语法,但会或多或少与以下内容匹配:

CREATE TRIGGER tr_tablename_bd BEFORE DELETE ON tablename
  FOR EACH ROW BEGIN
    DELETE FROM tablename WHERE parentID = deleted.id
END;

上面的代码也适用于无限级别,而不仅仅是 3 个级别。您将需要删除一行,触发器将删除以下级别中的数据行或将已删除行标记为 parentID 的行。

然而,我隐约记得 MySQL 的一个问题,它无法启动级联触发器。这意味着 MySQL 由于另一个触发器上的操作而无法触发触发器。如果您正在使用的 MySQL 版本(甚至最新版本)中仍然存在该错误,则此代码将不起作用。但是,理论上它是完全可以的,并且肯定可以在所有其他具有触发器的数据库上工作。对于 MySQL,您只需要检查他们是否已设法解决该错误!

于 2013-04-16T19:19:50.243 回答