Триггер instead of не может быть рекурсивным?

maitakov
Дата: 14.10.2003 18:06:47
Привет всем!\r
\r
Имеем таблицу, хранящую иерархическую информацию:\r
\r
create table Дерево\r
(Id int primary key\r
,Родитель int constraint Папаша references Дерево(Id)\r
,Название varchar(64)\r
)\r
\r
Хотелось бы при удалении любого узла одновременно удалять все подчиненное поддерево. Конструкция \r
\r
create table Дерево\r
(Id int primary key\r
,Родитель int constraint Папаша references Дерево(Id) on delete cascade\r
,Название varchar(64)\r
)\r
\r
не проходит:\r
\r
Msg 1785, Level 16, State 0, Line 1\r
Introducing FOREIGN KEY constraint \'Папаша\' on table \'Дерево\' may cause cycles or multiple cascade paths.\r
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
\r
\r
Ограничиваемся первым вариантом таблицы и создаем рекурсивный триггер:\r
\r
create trigger Топор on Дерево instead of delete as\r
\r
delete Дерево from deleted\r
where Дерево.Родитель = deleted.Id\r
\r
if @@error = 0\r
delete Дерево from deleted\r
where Дерево.Родитель = deleted.Id\r
go\r
ALTER DATABASE Лес SET RECURSIVE_TRIGGERS ON\r
go
\r
Формируем дерево:\r
\r
insert Дерево1\r
select 0, 0, \'Корень\'\r
union\r
select 1, 0, \'Ствол1\'\r
union\r
select 2, 0, \'Ствол2\'\r
union\r
select 3, 1, \'Сук11\'\r
union\r
select 4, 1, \'Сук12\'\r
union\r
select 5, 2, \'Сук21\'\r
union\r
select 6, 2, \'Сук22\'\r
union\r
select 7, 2, \'Сук23\'\r
union\r
select 8, 3, \'Лист111\'\r
union\r
select 9, 3, \'Лист112\'\r
union\r
select 10, 4, \'Лист121\'\r
union\r
select 11, 4, \'Лист122\'
\r
и тестируем триггер:\r
\r
delete Дерево1 where Id = 2
\r
Command(s) completed successfully\r
\r
delete Дерево1 where Id = 1
\r
Msg 547, Level 16, State 0, Procedure _123, Line 3\r
DELETE statement conflicted with COLUMN SAME TABLE REFERENCE constraint \'Папаша\'.\r
The conflict occurred in database \'Лес\', table \'Дерево\', column \'Родитель\'.
\r
\r
Тестирование показывает, что триггер успешно удаляет узел вместе с подчиненными узлами только в том случае, если он имеет только детей в первом колене (не имеет внуков). Отладка показывает, что первый delete в триггере не вызывает его повторно, хотя все прочие рекурсивные триггеры (не instead of) работают корректно.\r
\r
Что это - баг? фича? нормальное поведение? MSDE?\r
\r
SQL Server Desktop Engine - 8.00.760 (SP3) \r
Windows NT 5.0 (Build 2195: Service Pack 4)
\r
\r
На /topic/52247 vdimas предлагал, насколько я понимаю, именно этот вариант решения проблемы, но у меня он не работает. Подскажите кто знает, достал!!!\r
\r
maitakov.
Glory
Дата: 14.10.2003 18:20:27
Рекурсия вполне легко заменяется циклом.
maitakov
Дата: 14.10.2003 18:33:49
Конечно, вариантов решения много. Но здесь речь идет о принципиальных особенностях поведения MS SQL Server (см. название топика). Я чувствую себя неуютно, если работаю с инструментарием, логику которого я не понимаю.

maitakov.
maitakov
Дата: 14.10.2003 19:27:24
В тексте триггера Топор в стартовом сообщении топика допущена опечатка (copy-paste :-( )!!!

Правильный текст:
create trigger Топор on Дерево instead of delete as


delete Дерево from deleted
where Дерево.Родитель = deleted.Id

if @@error = 0
delete Дерево from deleted
where Дерево.Id = deleted.Id
go

Примите мои извинения!
iSestrin
Дата: 15.10.2003 07:53:23
>Триггер instead of не может быть рекурсивным?< - не может, заглянул в тфм, там это описано:
"If an INSTEAD OF trigger defined on a table executes a statement against the table that would usually fire the INSTEAD OF trigger again, the trigger is not called recursively."