[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Рекурсивное удаление
lans8097
Доброго времени суток форумчани.

Есть табличка

CREATE TABLE IF NOT EXISTS `category` (
`id` int(10) NOT NULL AUTO_INCREMENT, /*Идентификатор раздела*/
`sweat_category` int(10) NOT NULL DEFAULT '0', /*Идентификатор под раздела*/
PRIMARY KEY (`id`),
INDEX `ixSweatCategory` (`sweat_category`)
)
ENGINE=InnoDB;


Предположим есть категория
категория 1 -> куклы -> Барби -> Что-то ещо;
категория 1 -> Плюшевые игрушки -> Фирма Авалон;
категория 1 -> Роботы;

Как мы видим у категории нет лимита по вложенности и данная задача требует рекурсивных подход.
Задача нужно удалить категорию Куклы и все её пот категории и их поткатегории.
Как можно это реализовать на уровне MySql ?
Placido
Самый простой путь - при создании таблицы поставить внешний ключ на поле `sweat_category` с параметром "ON DELETE CASCADE":
CREATE TABLE `category` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`sweat_category` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT FOREIGN KEY (`sweat_category`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB

Тогда при удалении записи будут автоматически удаляться и все ее "дочерние" узлы.
glock18
Решения готового для вас не могу предложить (кроме очевидных, разумеется).

С одной стороны, можно было бы попробовать положиться на внешние ключи. Можно было бы, если бы они в мускуле работали так, как должны, ан-нет. Их валидация происходит не после выполнения всего запроса, а после удаления каждой отдельной записи. Попробовать, конечно, можно, сам не проверял конкретно этот случай, но с последствиями этого идиотского поведения постоянно приходится иметь дело.

Второе - многотабличный delete. Разумеется, здесь не идет речь о неограниченной глубине, ну а, скажем, запросом типа

delete a, a2, a3, a4
from tableA a
left join tableA a2 on a.id = a2.parent_id
left join tableA a3 on a2.id = a3.parent_id
left join tableA a4 on a3.id = a4.parent_id
where a.id = 100

выглядит не очень симпатично, но если
1. глубина может быть ограничена
2. внешние ключи не пашут

то такое решение, пожалуй, будет наиболее коротким и правильным.

PS:
еще есть вариант использовать хранимую процедуру, куда всунуть всю логику по удалению потомков. Получится не шибко красиво, но вся некрасота будет на стороне mysql, если это важно
lans8097
Цитата (Placido @ 20.07.2013 - 15:36)
Самый простой путь - при создании таблицы поставить внешний ключ на поле `sweat_category` с параметром "ON DELETE CASCADE":
CREATE TABLE `category` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`sweat_category` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT FOREIGN KEY (`sweat_category`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB

Тогда при удалении записи будут автоматически удаляться и все ее "дочерние" узлы.

Хм да так работает. но вот теперь стала вот такая проблема.
А именно при добавлении корневого раздела возникнит ошибка целостности веть категории 0 не существует
lans8097
Цитата (glock18 @ 20.07.2013 - 15:44)
Решения готового для вас не могу предложить (кроме очевидных, разумеется).

С одной стороны, можно было бы попробовать положиться на внешние ключи. Можно было бы, если бы они в мускуле работали так, как должны, ан-нет. Их валидация происходит не после выполнения всего запроса, а после удаления каждой отдельной записи. Попробовать, конечно, можно, сам не проверял конкретно этот случай, но с последствиями этого идиотского поведения постоянно приходится иметь дело.

Второе - многотабличный delete. Разумеется, здесь не идет речь о неограниченной глубине, ну а, скажем, запросом типа

delete a, a2, a3, a4
from tableA a
left join tableA a2 on a.id = a2.parent_id
left join tableA a3 on a2.id = a3.parent_id
left join tableA a4 on a3.id = a4.parent_id
where a.id = 100

выглядит не очень симпатично, но если
1. глубина может быть ограничена
2. внешние ключи не пашут

то такое решение, пожалуй, будет наиболее коротким и правильным.

PS:
еще есть вариант использовать хранимую процедуру, куда всунуть всю логику по удалению потомков. Получится не шибко красиво, но вся некрасота будет на стороне mysql, если это важно

Проблема какрас в том что нужно сделать безлимитный уровень.
Раньше всё это я делал на стороне php но это выходит слишком много лишних запросов, да это идиничные случии и нагрузки от них особой не будит но всёже хочится сделать всё по красоте на староне самой базы
lans8097
Цитата (lans8097 @ 20.07.2013 - 17:49)
Цитата (Placido @ 20.07.2013 - 15:36)
Самый простой путь - при создании таблицы поставить внешний ключ на поле `sweat_category` с параметром "ON DELETE CASCADE":
CREATE TABLE `category` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `sweat_category` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT FOREIGN KEY (`sweat_category`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB

Тогда при удалении записи будут автоматически удаляться и все ее "дочерние" узлы.

Хм да так работает. но вот теперь стала вот такая проблема.
А именно при добавлении корневого раздела возникнит ошибка целостности веть категории 0 не существует

Обход данной проблемы прост всеголиш включаем и выключаем данную вещь.

CREATE TABLE `category2` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`sweat_category` int(10) DEFAULT NULL,
`name` VARCHAR(255) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT FOREIGN KEY (`sweat_category`) REFERENCES `category2` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
SET FOREIGN_KEY_CHECKS=0;
INSERT into `gumped_beta`.`category2` (`sweat_category`,`name`) VALUES ('0','Корневая категория');
SET FOREIGN_KEY_CHECKS=1;

но может можно вставить какието дополнительные свойства условия для решения данной проблемы
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.