0

从表递归地指向自身的给定记录ID中删除后代记录的策略是什么?具体来说,我使用的是 PDO、PHP 和 MySQL 5.0+。

想象一个包含这些列的类别表:

  • ID
  • parent_id
  • 分类名称

如果 ID 为 0,则它是根类别。请注意,该 id 不是主键 - 可以有许多根类别。

想象它有好几层深,比如 Food 和 Shelter 根类别,然后是它们的子类,以及它们的子类,等等。这些是后代。例如,如果有人要删除蔬菜,那么您可以预期食物和庇护所将作为根类别留下,但胡萝卜会消失,豆类也会消失。豪宅和小屋也将被留下,因为它们来自另一棵树。得到它?

编辑:我的错——忘了一列——parent_id。这是非常关键的。

4

3 回答 3

2

但是,在您的场景中可能不是选项,用于存储分层数据的嵌套集模型可以使您描述的操作非常有效。

这篇文章也可能有用:

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

于 2011-12-16T21:29:47.783 回答
1

一个简单的级联参照完整性应该做到这一点 - 使用 ON DELETE CASCADE 声明您的 FOREIGN KEY。而且,如果您对parent_id.

例如:

CREATE TABLE your_table (
    id int PRIMARY KEY,
    parent_id int DEFAULT NULL,
    category_name varchar(45) NOT NULL,
    -- Will also create index on parent_id:
    CONSTRAINT your_table_fk1 FOREIGN KEY (parent_id) REFERENCES your_table (id)
        ON DELETE CASCADE
);

INSERT INTO your_table (id, category_name) VALUES (1, 'Food');
INSERT INTO your_table (id, category_name) VALUES (2, 'Shelter');
INSERT INTO your_table (id, parent_id, category_name) VALUES (3, 1, 'Vegetables');
INSERT INTO your_table (id, parent_id, category_name) VALUES (4, 3, 'Carrots');
INSERT INTO your_table (id, parent_id, category_name) VALUES (5, 3, 'Beans');
INSERT INTO your_table (id, parent_id, category_name) VALUES (7, 2, 'Mansions');
INSERT INTO your_table (id, parent_id, category_name) VALUES (8, 2, 'Cabins');

那么当你执行...

DELETE FROM your_table WHERE category_name = 'Vegetables'

...不仅“蔬菜”,“胡萝卜”和“豆类”也将被删除。

这甚至可以递归地工作,所以......

DELETE FROM your_table WHERE category_name = 'Food'

...在第一级删除“食物”,在第二级删除“蔬菜”,在第三级删除“胡萝卜”和“豆类”。

于 2011-12-18T05:11:16.133 回答
0

尽管嵌套集模型更强大,但有时以下带有递归的示例就足够了。

public function deleteCategory($sCatID) {
  if (empty($sCatID)) {
    return FALSE;
  }
  // you can get your PDO database connection your own way -- this is my way for my framework
  $PDO = $this->data->mysql();
  // recursively find all the descendents of this category and delete those too
  $sSQL = "
  SELECT
    `id`
  FROM
    `categories`
  WHERE
    `parent_id` = :parent_id;
  ";
  $st = $PDO->prepare($sSQL);
  $st->bindValue(':parent_id',$sCatID);
  try {
    $st->execute();
    $rsRows = $st->fetchAll();
    foreach($rsRows as $rwRow) {
      $sChildCatID = $rwRow['id'];
      // note the recursion here!
      $this->deleteCategory($sChildCatID);
    }
  } catch (PDOException $e) {}
  unset($st);
  // now delete this category
  $sSQL = "
  DELETE FROM
    `categories`
  WHERE
    `id` = :id
  LIMIT 1;
  ";
  $st = $PDO->prepare($sSQL);
  $st->bindValue(':id',$sCatID);
  try {
    $st->execute();
  } catch (PDOException $e){}
}
于 2011-12-16T21:57:38.643 回答