从表中删除嵌套类别

时间:2011-09-28 13:39:40

标签: php mysql

我有一个名为categories的表,看起来像这样

+-------------+--------------+---------------+
|  id         |  catName     |  parentId     |
+-------------+--------------+---------------+
|  1          | Category 1   |  0            |
|  2          | Category 2   |  0            |
|  3          | Sub Cat 1    |  1            |
|  4          | Sub Cat 2    |  1            |
|  5          | Sub sub cat 1|  4            |
|  6          | Sub sub cat 2|  4            |
|  7          | Category 2   |  0            |
+-------------+--------------+---------------+

删除一个类别及其直接子项会很容易:

mysql_query("DELETE FROM `categories` WHERE `id`='$id'");
mysql_query("DELETE FROM `categories` WHERE `parentId`='$id'");

但是我需要能够删除某个类别的所有孩子。例如,如果Category 1被删除Sub Cat 1,则Sub Cat 2Sub sub cat 1Sub sub cat 2将被删除

任何帮助表示感谢。

5 个答案:

答案 0 :(得分:1)

你可以使用foreign keys,一个非常好的mysql功能。这是一种用于引用不同关系的完整性检查。例如,如果创建外键,mysql会确保存在引用的条目。在创建外键期间,您可以定义如果删除“父元素”,mysql应该执行的操作。您可以指定“SET NULL”,“UPDATE”或“DELETE CASCADE”。这意味着,如果删除类别,则也会删除每个连接的子类别。并且由于每个子类别都是子子类别的父类别,因此也会删除它们。

答案 1 :(得分:1)

这是一个简单的递归脚本,用于删除您的类别和嵌套在其中的所有嵌套类别。

try {

$db = new PDO(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
}catch( PDOException $e ) {
    echo $e->getMessage();
}



class Category {



function delete_category($parrent){
    global $db;
    $stmt = $db->prepare("SELECT `id` FROM `categories` WHERE `parrentId`=:parrentId");
    $stmt->execute(array('parrentId'=>$parrent));
    while($category = $stmt->fetchObject('Category')){
        $category->delete_category($category->id);
    }
        $stmt = $db->prepare("DELETE FROM `category` WHERE `id` = :id");
        $stmt->execute(array('id'=>$parrent));

}



function __construct(array $data = NULL) {
    if( empty($data) )
    return;

    foreach( $data as $field => $value ) {
        $this->$field = $value;
    }
}}

其中$ db是用于连接数据库的PDO对象。它可能有一些错误,因为我只是修改我的以适应您的问题。希望这会有所帮助。

PS:用于调用您的函数:$category=new Category(); $category->delete_category($_GET['id'])

答案 2 :(得分:0)

为了清晰起见,引用了我的原始答案。

更新1:表格拆分的问题在于,不清楚是否存在固定数量的子,子类别。为了实现这一点,您需要分割成与子类别一样多的表,每个子类都将外键返回到其父ID。如果子(或子子)类别的数量是动态的,则不实用。

  

在这种情况下,我认为你会有所改变   桌子设计。如果将两个表拆分为类别和   您可以利用外键的子类别   strauberry描述的功能。例如(这些没有   看起来像桌子,但希望这是有道理的)括号中的东西   是解释:

     

类别

     
      
  • id(主键)
  •   
  • catName
  •   
     

子类

     
      
  • sub_id(主键)
  •   
  • id(类别表的主键引用的外键)
  •   
  • subCatName
  •   
     

然后在创建类别表时,可以使用ON DELETE   CASCADE选项。这意味着每当您删除类别时   从类别表中,所有相关的子类别   子类表将由MySQL自动删除。   功能强大,减少了代码,您无需确保所有代码   删除操作在右表中手动进行。希望澄清一个   小。

更新2:此选项的问题是,它不起作用:) MySQL将不允许您在正在执行DELETE的同一个表上进行子查询。所以最初看起来是一个简单的问题......不是。

  

如果您无法更改表格设计,则可以执行以下操作   (替换您实际想要删除的ID   category_id_to_delete):

DELETE FROM categories
WHERE id = category_id_to_delete OR id IN (
    SELECT id
    FROM categories
    WHERE parentID = category_id_to_delete
)

所以,我做了一些检查,并在SO MySQL: How to find all IDs of children recursively?上遇到了类似的问题,并且评分最高的答案指向了这篇文章Managing Hierarchical Data in MySQL。该文章指出了您需要用于选择数据的LEFT JOINS查询类型,但没有明确说明如何删除该数据。推荐的解决方案是使用与文章中相邻集相关的查询来选择所需的所有id信息,然后在你的代码中(我认为是php?)循环这些id并构造一个新的查询来删除它们。

例如,如果您尝试删除类别1(id = 1),那么通过循环来自文章LEFT JOIN查询的ID的目标是创建另一个看起来像的查询:

DELETE FROM categories
WHERE id IN (1,3,4,5,6);

此论坛帖子中的代码也可以帮助您作为在PHP中递归执行此操作的方法:Adjacency List Model recursive deletion

我知道这不是一个干净整洁的答案,但也许这会指出你正确的方向。

答案 3 :(得分:0)

演示mysql“cascade on delete”功能。如果你在控制台中运行它,那么你可以立即运行所有查询,输出将是有意义的。如果你在某个图形工具中运行它,那么我想你必须逐个运行查询。

CREATE DATABASE `recursivedemo`;

USE `recursivedemo`;

CREATE TABLE `categories` (
    `id` INT AUTO_INCREMENT,
    `catName` VARCHAR(50),
    `parentId` INT,

    PRIMARY KEY (`id`),

    KEY `parentId` (`parentId`),
    CONSTRAINT `categories_fk_self` FOREIGN KEY (`parentId`) REFERENCES `categories`(`id`) ON DELETE CASCADE
) Engine=InnoDB;

SELECT * FROM `categories`;

INSERT INTO `categories`(`catName`, `parentId`) VALUES('Category 1', NULL);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Category 2', NULL);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 1.1', 1);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 1.2', 1);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub sub cat 1.2.1', 4);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub sub cat 1.2.2', 4);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 2.1', 2);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 2.2', 2);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Category 3', NULL);

SELECT * FROM `categories`;

DELETE FROM `categories` WHERE `id`=1;

SELECT * FROM `categories`;

DROP DATABASE `recursivedemo`;

答案 4 :(得分:0)

您可以在模型中对已删除的嵌套类别使用以下函数:

 public function delete_by_id($cat_id)
{
     $this->db->delete('Categories', ['cat_id' => $cat_id]);
            $q = $this->db->where('parent_id', $cat_id)->get('Categories');
        foreach( $q->result() as $Child ) {
            $this->delete_by_id($Child->cat_id);
        }
}