Php 从表中删除嵌套类别

Php 从表中删除嵌套类别,php,mysql,Php,Mysql,我有一个名为categories的表,看起来像这样 +-------------+--------------+---------------+ | id | catName | parentId | +-------------+--------------+---------------+ | 1 | Category 1 | 0 | | 2 | Category 2 | 0

我有一个名为
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'");
但是,我需要能够删除一个类别的所有子项。例如,如果
类别1
被删除
子类别1
子类别2
子类别1
子类别2
将被删除


感谢您的帮助。

您可以使用,这是mysql非常好的功能。这是一种用于引用不同关系的完整性检查。例如,如果创建外键,mysql将确保引用的条目存在。在创建外键的过程中,您可以定义如果删除了“父元素”,mysql应该做什么。您可以指定“设置空”、“更新”或“删除级联”。这意味着,如果删除一个类别,则每个连接的子类别也将被删除。由于每个子类别都是子类别的父类别,因此这些子类别也会被删除。

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

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

在这种情况下,我认为你改变自己的想法会有好处 桌子设计。如果将两个表拆分为类别和 可以利用外键的子类别 Straubery描述的功能。例如(这些不是 看起来像表格,但希望这是有意义的)括号里的东西 解释如下:

类别

  • id(主键)
  • 猫名
子类别

  • 子单元id(主键)
  • id(引用类别表主键的外键)
  • 子目录名
然后,在创建categories表时,可以使用ON DELETE 级联选项。这意味着无论何时删除类别 从“类别”表中,选择 MySQL将自动为您删除子类别表。 功能强大,并且减少了代码,您不必确保所有 在正确的表中手动执行删除操作。希望这能澄清一个问题 很少

更新2:这个选项的问题是,它不起作用:)MySQL将不允许您在执行删除操作的同一个表上进行子查询。所以一开始看起来是个简单的问题。。。不是

如果无法更改表设计,则可以执行以下操作 (替换实际要删除的id 类别(要删除的id):

因此,我做了一些进一步的检查,并在这篇文章中遇到了类似的问题,而这篇文章的最高评分答案是。那篇文章指出了需要使用左连接来选择数据的查询类型,但没有明确介绍如何删除该数据。推荐的解决方案是使用本文中与相邻集合相关的查询来选择所需的所有id信息,然后在代码(我想是php?)中循环这些id并构造一个新的查询来删除它们

例如,如果您试图删除类别1(id=1),则通过循环文章中左连接查询的id,您的目标是创建另一个如下所示的查询:

DELETE FROM categories
WHERE id IN (1,3,4,5,6);
本论坛帖子中的代码也可以帮助您在php中递归地执行此操作:


我知道这不是一个简洁明了的答案,但也许这将为您指明正确的方向。

mysql“删除时级联”功能的演示。如果您在控制台中运行此命令,那么您可以一次运行所有查询,并且输出将有意义。如果您在某个图形工具中运行它,那么我想您必须逐个运行查询

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`;

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

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=newcategory();

$category->delete\u category($\u GET['id'])

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

 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);
        }
}

请你详细说明一下好吗?谢谢!只需要想想如何使用创建外键:)你可以使用phpMyAdmin或者看看这个网站:我正在使用phpMyAdmin,我刚刚将引擎从MyISAM切换到innoDB,但我仍然找不到选项??:我们找到了!我会让您知道我在现阶段无法更改桌子设计的原因:(还有其他选项吗?可能是代码?上面更新了答案,但我在手机上,所以格式和语法可能不确定。使用前请仔细检查。上面的编辑还假设id是唯一的,因此给定类别的parentid是唯一的。hmmmm我收到此错误
您无法指定从claus更新的目标表“categories”e
@Lee Price是的,我明白了。MySQL不会让你在删除查询的同一个表上执行子查询。我会更新我的答案。再检查一件事。我知道这会删除类别1和子类别1.1,但我不知道它如何删除子类别1.2.1和子类别1.2.2。也许你犯了我第一次阅读时犯的同样错误问题?:)删除parentId连接到顶级类别的第一个级别是一回事,但要删除到第一个子类别下未链接到parentId 1的较低级别是一个更难的问题。也许我在你的答案中遗漏了什么?@Carvelfenton是的,你遗漏了“如果您在控制台中运行此命令,则可以运行所有命令
 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);
        }
}