【问题标题】:Get parents recursive in right order for deletion from MySQL table让父母以正确的顺序递归以从 MySQL 表中删除
【发布时间】:2012-06-24 17:38:03
【问题描述】:

我有一个这样的表结构

mysql> SELECT id, name, parent_id FROM categories;
+-------+------------+-----------+
| id    | name       | parent_id |
+-------+------------+-----------+
| 15790 | Test       |         0 |
| 15791 | Test2      |         0 |
| 16079 | Subtest    |     15790 |
| 16080 | Subtest 2  |     15790 |
| 16081 | Subsubtest |     16079 |
+-------+------------+-----------+

现在我想查找每个孩子和兄弟姐妹的父母,并以正确的顺序将其返回以进行删除。

所以在这种情况下我的输出是:

Array
(
  16081,
  16080,
  16079,
  15791,
  15790
)

我不能仅通过反转父 ID 来删除,因为这应该是可靠的走回树。

我也不能/不允许更改表格的结构。所以建立某种索引是必要的。

【问题讨论】:

  • 抱歉,触发器是什么意思?
  • 您能解释一下“正确的删除顺序”是什么意思吗?
  • @KeithRandall 当然:所有子类别(及其同级)必须在其父类别之前 删除。没什么特别的,但我不知道该怎么做。
  • @DanLee,当您尝试删除其子行之前的行时,这是由于外键约束错误吗?
  • 选择语句中使用的标准是什么?您是否打算删除记录并且需要检查并删除任何子、孙等?会有孙子及以下吗?

标签: php mysql recursion parent children


【解决方案1】:

假设您无权访问TRUNCATE、SET(因此您可以访问SET FOREIGN_KEY_CHECKS=0;)、ALTER 等,并且绝对必须 使用脚本:

由于问题被标记为php,这应该可以解决问题:

function reversetree($src_arr, $currentid = 0)
{
    $cats = array();
    foreach($src_arr as $id => $parent)
    {   
        if($parent == $currentid)
        {
            $cats[] = $id;
            $cats = array_merge($cats, reversetree($src_arr, $id));
        }
    }
    return !$currentid ? array_reverse($cats) : $cats;
}

$rs = array();
foreach($pdo->query('SELECT id, parent_id FROM categories') as $row)
    $rs[$row['id']] = $row['parent_id'];

$stmt = $pdo->prepare('DELETE FROM categories WHERE id = ?');

$pdo->beginTransaction();
foreach(reversetree($rs) as $v)
    $stmt->execute(array($v));
$pdo->commit();

【讨论】:

  • 这是正确答案,谢谢赞恩! (您将尽快获得奖励)
【解决方案2】:

我不明白为什么您需要按特定顺序排列 ID。您可以通过事务删除它们,它们将同时被删除。

DELETE FROM categories WHERE ID IN (15790,15791,16079,16080,16081);

【讨论】:

  • 这是正确的 (+1)。但是您可能需要连续多次运行查询;乱序删除可能会导致错误,因此查询可能需要重复运行。
  • 是的,我也想过暴力破解它,但是在黑暗的某个地方还有其他依赖项,我不想知道。数据库设计存在几个问题,应该明确解决。
【解决方案3】:

您可以在 DELETE 上使用 CASCADE 添加 FOREIGN KEY 约束。 外键将指向父 id 字段上的同一个表。

当您删除父级时,所有子级(无论哪个级别)都会自动删除。

【讨论】:

  • 不幸的是,我无法更改表结构的任何内容。不过,感谢您的宝贵时间。
【解决方案4】:
<?php

// housekeeping
$pdo = new PDO($dsn, $user, $password);
$select = $pdo->prepare(
    "SELECT parent.id AS parent_id, child.id AS child_id
    FROM categories AS parent
    JOIN categories AS child ON parent.id = child.parent_id
    WHERE parent.id = ?"
);
$delete = $pdo->prepare('DELETE FROM categories WHERE id = ?');

// deletes $node_id, deletes its children first if required
function delete_node($node_id){
    $select->execute( array($node_id) );
    $children = $select->fetchAll(PDO::FETCH_NUM);
    if (count($children) !== 0) { // if 0, then the category does not exist, or it has no child
        foreach ($children as $child) { // call delete_node() recursively on each child
            delete_node ($child[1]);
        }
    }
    $delete->execute( array($node_id) ); // then delete this node (or do nothing if $node_id does not exist)
}


// to delete one category and all its sub-categories

delete_node(15790);

// to delete all contents

$allTopLevel = $pdo->exec('SELECT id FROM categories WHERE parent_id = 0')->fetchAll(PDO::FETCH_NUM);
foreach ($allTopLevel as $node) {
    delete_node($node[0]);
}

未测试,甚至不确定它是否“编译”,但你明白了。确保在调用delete_node() 之前锁定表(或启动事务)。

【讨论】:

  • 问题是过度使用查询,一个应该足以建立索引(见Zanes回复)。但是感谢您的时间,我相信这个也可以:)
  • 绝对正确,我只是想递归地做,正如标签所暗示的那样。 Zane Bien 的代码执行得更快。
  • @DanLee 虽然id 和parent_id 被索引,MySQL 应该只能在内存中工作。但是,这个解决方案仍然很糟糕。
【解决方案5】:

对不起,我帮不上什么忙,因为 SQL 不是我的菜。但也许有人可以将 java 伪代码转移到解决方案中

delete(table.getFirstRow().get(id));

delete(id_a){
    for(data_set : table)
        if(data_set.get(parent_id) == id_a)delete(data_set.get(id));
    }
    table.remove(id_a);
}

编辑:没有关于元素的迭代?所以是这样的吗?

delete(list){
    if(list.size() == 0)return;
    idList = list.getAll(id);
    plist = table.getAllWhichEquals(parent_id, idList);
    delete(plist);
    table.remove(idList);
}

啊,算了,我不是同时删除,只是试一试^^

【讨论】:

  • 如果可以遍历记录那就太好了;但 SQL 是单程的。
猜你喜欢
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-20
  • 2012-05-16
相关资源
最近更新 更多