-- drop table role;
create table role
(   id int not null auto_increment primary key, -- for kicks and if i screw up
    roleId int not null,    -- i will manually provide it so i can see it
    parent int null,
    unique index (roleId)
);
insert role(roleId,parent) values (1,null),(2,null),(3,2),(4,3),(5,3),(6,3),(7,4),(8,3),(9,6),(10,6),(11,10);
-- if i want to delete roleId A then i need to delete anything with a parent=A (B) and all of B's lineage too
-- drop procedure deleteParentDownwards;
delimiter $$
create procedure deleteParentDownwards
(
deleteMe int
)
BEGIN
    -- deleteMe parameter means i am anywhere in hierarchy of role
    -- and i want me and all my offspring deleted (no orphaning of children or theirs)
    declare bDoneYet boolean default false;
    declare working_on int;
    declare theCount int;
    CREATE TABLE xxDeleteRoleHierarchyxx
    (
        roleId int not null,
        processed int not null
    );
    set bDoneYet=false;
    insert into xxDeleteRoleHierarchyxx (roleId,processed) select deleteMe,0;
    while (!bDoneYet) do
        select count(*) into theCount from xxDeleteRoleHierarchyxx where processed=0;
        if (theCount=0) then 
            -- found em all
            set bDoneYet=true;
        else
            -- one not processed yet, insert its children for processing
            SELECT roleId INTO working_on FROM xxDeleteRoleHierarchyxx where processed=0 limit 1;
            insert into xxDeleteRoleHierarchyxx (roleId,processed)
            select roleId,0 from role
            where parent=working_on;
            -- mark the one we "processed for children" as processed
            update xxDeleteRoleHierarchyxx set processed=1 where roleId=working_on;
        end if;
    end while;
    delete from role where roleId in (select roleId from xxDeleteRoleHierarchyxx);
    drop table xxDeleteRoleHierarchyxx;
END
$$
call deleteParentDownwards(3); -- deletes many
call deleteParentDownwards(6); -- deletes 4 (assuming line above was not called first!)