У меня есть иерархическая система, которая хранит уровень и родительский идентификатор элемента в базе данных. Я пытаюсь выяснить, как я могу найти все дочерние строки того, который выбирает пользователь. Вот пример структуры таблицы:
+----+---------+----------+-------+ | Id | label | parentid | level | +----+---------+----------+-------+ | 1 | honda | 0 | 1 | | 2 | accord | 1 | 2 | | 3 | civic | 1 | 2 | | 4 | element | 1 | 2 | | 5 | v4 | 2 | 3 | | 6 | v6 | 2 | 3 | +----+---------+----------+-------+
Итак, если кто-то удалит honda
, как я могу удалить все иерархию? База данных будет только до уровня 3.
Refer, Рекурсивный MySQL-запрос с реляционным innoDB
Вчера я опубликовал ответ для того же
Обновить:
Ниже приведена function
основанная на вышеуказанной ссылке, но была настроена для ваших требований DELETE
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
использование
CALL delete_relations(1)
Чтобы удалить все записи и их отношения для id = 1 honda
Надеюсь, что это полезно
Заменить :id
помощью :id
корневой записи, который необходимо удалить, в следующем:
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 )
Обратите внимание, что у вас есть 3 уровня, но корневой узел занимает один из них, а это значит, что вам нужно только выбрать детей и внуков. Вышеуказанный запрос делает еще один уровень (третий), поэтому вы можете удалить часть после -- third level
до закрывающей круглой скобки.
Предполагая, что вы находитесь на MySQL 5, у которого есть триггеры, вы можете написать небольшой перед триггером удаления, чтобы достичь этого легко. Я точно не проверял синтаксис, но будет соответствовать более или менее следующим:
CREATE TRIGGER tr_tablename_bd BEFORE DELETE ON tablename FOR EACH ROW BEGIN DELETE FROM tablename WHERE parentID = deleted.id END;
Вышеприведенный код также будет работать с неограниченными уровнями, а не только с 3 уровнями. Вам нужно будет удалить строку, и триггер будет удалять строки данных на нижележащих уровнях или строках, которые отмечают удаленную строку как parentID.
Однако я смутно помню проблему с MySQL, в которой ему не удалось запустить каскадные триггеры. Значение MySQL не запускает триггер из-за действия на другой триггер. Если эта ошибка все еще существует в выпуске MySQL, который вы используете (или даже последнее издание), тогда этот код не будет работать. Тем не менее, теоретически это совершенно нормально и будет работать над любой другой базой данных, в которой есть триггеры. Для MySQL вам просто нужно проверить, удалось ли решить эту ошибку!