I have a hierarchy system setup that stores the level and parent ID of the item in a database. What I am trying to figure out is how would I go about finding all the child rows
Assuming you are on MySQL 5 that has triggers you can write a small before delete trigger to achieve this easily. I have not checked the syntax exactly but will match more or less with the following:
CREATE TRIGGER tr_tablename_bd BEFORE DELETE ON tablename
FOR EACH ROW BEGIN
DELETE FROM tablename WHERE parentID = deleted.id
END;
The above code will also work with unlimited levels and not just 3 levels. You will need to delete a row and the trigger will delete the rows of data in the below levels or rows that mark the deleted row as parentID.
I however, vaguely remember an issue with MySQL wherein it failed to launch cascaded triggers. Meaning MySQL fails to fire a trigger due to an action on another trigger. If that bug is still there in the release of MySQL you are using (or even the latest edition) then this code will not work. However, in theory it is perfectly ok and will work on every other database that has triggers for sure. For MySQL you just need to check up if they have managed to resolve that bug yet!
Replace :id
by the root entry id to be deleted in the following:
DELETE FROM table
WHERE
id = :id
OR id IN (
-- first level
SELECT DISTINCT id sid
FROM table
WHERE parentid = :id
-- second level
UNION
SELECT DISTINCT t2.id sid
FROM table t1
INNER JOIN table t2
ON t1.id = t2.parentid
WHERE t1.parentid = :id
-- third level
UNION
SELECT DISTINCT t3.id sid
FROM table t1
INNER JOIN table t2
ON t1.id = t2.parentid
INNER JOIN table t3
ON t2.id = t3.parentid
WHERE t1.id = :id
)
Note that you have 3 levels, but the root node occupies one of them, which means that you actually only need to select the children and grandchildren. The query above does one more level (the 3rd one), so you may remove the part after -- third level
down to the closing parenthesis.
Refer, Recursive MySQL Query with relational innoDB
I had posted a answer yesterday for the same
Update:
Below is a function
based on the above link, but has been tailored for your DELETE
requirements
CREATE PROCEDURE `delete_relations`(`_id` INT)
BEGIN
DECLARE delete_row_ids varchar(200);
DECLARE id, id2 varchar(200);
DECLARE rows_affected int;
SET delete_row_ids = _id;
SET id = _id;
SET id2 = id;
WHILE id2 IS NOT NULL DO
SET id = NULL;
SELECT GROUP_CONCAT( hierarchical_data.id ), CONCAT( GROUP_CONCAT( hierarchical_data.ID ),',',delete_row_ids) INTO id, delete_row_ids FROM hierarchical_data WHERE FIND_IN_SET( parentid , id2 ) GROUP BY parentid ;
SET id2 = id;
END WHILE;
DELETE FROM hierarchical_data where FIND_IN_SET(hierarchical_data.id, delete_row_ids);
SELECT row_count() INTO rows_affected;
if rows_affected > 0 THEN
SELECT delete_row_ids as row_ids_deleted;
ELSE
SELECT 'NO_ROWS_DELETED';
END IF;
END//
SQLFiddle
Use
CALL delete_relations(1)
To delete all entries and its relations for id = 1 honda
Hope its helpful