简体   繁体   English

如何在 MySQL 中删除带有子项的多级菜单项?

[英]How to remove multi-level menu item with children in MySQL?

I have unlimited level menu structure in MySQL, where parent and children elements are connected with column p_id :我在 MySQL 中有无限级别的菜单结构,其中父元素和子元素与列p_id连接:

+----+------+------+----------------+
| id | p_id | sort | name_en        |
+----+------+------+----------------+
|  1 |    0 |    1 | menu-1         |
|  2 |    0 |    2 | menu-2         |
|  3 |    0 |    6 | menu-3         |
|  4 |    2 |    3 | sub-menu-2-1   |
|  5 |    2 |    4 | sub-menu-2-2   |
|  6 |    5 |    5 | sub-menu-2-2-1 |
+----+------+------+----------------|

What is best practice for deleting root menu element with sub-menu elements?删除带有子菜单元素的根菜单元素的最佳做法是什么?

I can achieve it with PHP recursion, but it will cause some number of queries.我可以用 PHP 递归来实现它,但它会导致一些查询。

So I need to find out if is there any possible way to do it with one MySQL query.所以我需要找出是否有任何可能的方法用一个 MySQL 查询来做到这一点。

Since you have name_en , cannot you use that one to delete the rows?既然你有name_en ,你不能用那个来删除行吗? For example,例如,

DELETE FROM `table` WHERE `id` = 2 OR `name_en` LIKE 'sub-menu-2-%'

New method:新方法:

You can use a Foreign Key with a constraint.您可以使用带有约束的外键 I created your table and called it treelist,我创建了你的表并将其命名为 treelist,

CREATE TABLE  `treelist` (
  `item_id` int(10) unsigned NOT NULL auto_increment,
  `parent_id` int(10) unsigned default NULL,
  `name_en` varchar(40) NOT NULL,
  PRIMARY KEY  (`item_id`),
  KEY `FK_parent_id` (`parent_id`),
  CONSTRAINT `FK_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `treelist` (`item_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

I then added some test data, the ones you had in your question,然后我添加了一些测试数据,你在问题中的那些,

INSERT INTO `treelist` (`item_id`, `parent_id`, `name_en`) VALUES (NULL, NULL, 'Menu 1'), (NULL, NULL, 'Menu 2'), (NULL, NULL, 'Menu 3'), (NULL, 2, 'Sub Menu 2-1'), (NULL, 2, 'Sub Menu 2-2'), (NULL, 5, 'Sub Menu 2-2-1');

Now, when you delete a row, for example现在,当您删除一行时,例如

DELETE FROM `treelist` WHERE `item_id` = 2

It will delete all children, grand-children etc as well.它还将删除所有子项、孙子项等。 Afterwards the table looks like,之后桌子看起来像,

+----+------+----------------+ 
| id | p_id | name_en        |
+----+------+----------------+ 
|  1 | NULL | Menu 1         | 
|  3 | NULL | Menu 3         |
+----+------+----------------+

To delete just a row and it's direct children (not grandchildren):只删除一行并且它是直接的子级(不是孙子级):

DELETE FROM tablename where id = 1 or p_id = 1;

UPDATE 1:更新1:

If you have freedom to add a column to the table, you could add root_id and easily do the delete based on that.如果您可以自由地向表中添加一列,您可以添加 root_id 并根据它轻松地进行删除。 This will not ruin any current queries in your system and will only take a one-time run of a simple script to add the initial data.这不会破坏您系统中的任何当前查询,并且只需运行一次简单脚本即可添加初始数据。

DELETE FROM tablename where id = 1 or root_id = 1;

UPDATE 2: A pretty awesome option is that foreign keys to the same table are allowed.更新 2:一个非常棒的选择是允许同一个表的外键。 So you can add a foreign key to p_id that references id, use on delete cascade and when you delete the root, all descendants will be removed also.因此,您可以向 p_id 添加一个引用 id 的外键, on delete cascade使用,当您删除根时,所有后代也将被删除。 I created a test table and this worked beautifully for me.我创建了一个测试表,这对我来说效果很好。 It may also be beneficial to add on update cascade .添加on update cascade也可能是有益的。 Remember that p_id as well as id need to be unsigned for this to work.请记住,p_id 和 id 需要未签名才能工作。

ALTER TABLE tablename ADD CONSTRAINT fk_tablename_id FOREIGN KEY (p_id) references tablename(id) ON DELETE CASCADE;

Just category id or parent id in first parameter:第一个参数中仅包含类别 ID 或父 ID:

function delete_parent_and_child_subchild($category_id,$all_cate=array())
        {
            if(!is_array($category_id))
            {           
                $this->db->where('parent_id', $category_id);
                $all_cate[]=$category_id;
            }
            else
            {           
                $this->db->where_in('parent_id', $category_id);
            }        
            $get_categories= $this->db->get('newcategory'); 

            if($get_categories->num_rows()>0)
            {
                $categories_vales=$get_categories->result(); 
                $new_subcat = array();
                foreach($categories_vales as $cate_val)
                {
                    $category_id=$cate_val->category_id;
                    array_push($new_subcat,$category_id);
                }
                $all_cate = array_merge($all_cate,$new_subcat);         
                if(count($new_subcat)>0)
                {
                    $this->delete_parent_and_child_subchild($new_subcat,$all_cate);
                }   

            }   
            $this->db->where_in('category_id', $all_cate)->delete('newcategory');
            return true;
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM