views:

231

answers:

2

Hi,

I'm working on a project that has categories / subcategories. The database table for this is unique, with the following structure :

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL auto_increment,
  `publish` tinyint(1) NOT NULL default '0',
  `parent_id` int(11) NOT NULL default '0',
  `description` text NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

So, in case the category is a "base" one, the parent_id is zero, and if the category has a parent, it herds the parent id. What I want to know is this : I need to delete everything above and related with a category when choosing that option, a cascade-like deletion, but I only have this table (no foreign keys) .. How do I do that? (without a large amount of queries)

Thanks in advance!

+2  A: 
  • You can write a trigger to do it.

    DELIMITER //
    CREATE TRIGGER CatDelete AFTER DELETE ON categories
    FOR EACH ROW BEGIN
      DELETE FROM categories WHERE parent_id = old.id;
    END//
    DELIMITER ;
    
  • You can ALTER your MyISAM tables to InnoDB, and then define foreign key constraints with the ON DELETE CASCADE option.

    ALTER TABLE categories ENGINE=InnoDB;
    ALTER TABLE categories ADD CONSTRAINT 
      FOREIGN KEY (parent_id) REFERENCES categories (id) ON DELETE CASCADE;
    


Re your comment, the first thing I'd check is if you have some orphan categories, that is with parent_id pointing to a non-existant row. That would prevent you from creating the constraint.

SELECT c1.*
FROM categories c1
LEFT OUTER JOIN categories c2
  ON (c1.parent_id = c2.id)
WHERE c2.id IS NULL;
Bill Karwin
Looks good, Bill. One related question: isn't there a risk to introduce deadlocks with the first approach ?
mjv
As long as you don't have cycles in your "trees" I don't think so. It all counts as the same operation, so you're not contending for locks. Try it yourself with some test data.
Bill Karwin
I'm having problems with the second sollution : ALTER TABLE categories ADD FOREIGN KEY ( parent_id ) REFERENCES categories( id ) - MySQL didn't let me do that (the table is already in InnoDB). The error : Cannot add or update a child row: a foreign key constraint fails
yoda
@Bill Karwin, the thing is, when the category is at "level 0", it has no parent .. apparently, should I define a "master category" just for the foreign key to work?
yoda
Use NULL for the top level category in the hierarchy instead of zero.
Bill Karwin
@Bill Karwin, that doesn't make much sense to me .. how do I do that?
yoda
Ok, got it now .. Thanks for everyyhing!
yoda
+1  A: 

Just my $0.02 - this not so trivial solution should require MVC to handle the cascade deletion.

Eimantas
what do you mean by that?
yoda
in MVC frameworks there are models (the M part) which usually in web development handle interaction with databases. Usually developer would define models, relations between them (foo has one bar, foo has many bars, foo has and belongs to many bars) and on those relations you may define that given model deletets dependent models. So for category models you could say that:- it has many subcategories (with reference to self)- it deletes any subcategory entries when self is destroyed
Eimantas
I'm using kohana actually .. I'll try ORM methods, thanks for the advice ;)
yoda