Há uma declaração no final desta resposta aceita de que, se ocorrer um erro em um gatilho "For Delete", a ação de exclusão será revertida porque faz parte de uma transação implícita.
No entanto, aqui está um exemplo mostrando que as linhas excluídas permanecem excluídas mesmo que um erro seja gerado:
create table T1 ( i1 int );
go
create trigger T1_ForDelete on T1
for delete
as
raiserror('Raised 16', 16, 1);
raiserror('Raised 18', 18, 1);
raiserror('Raised #2 16', 16, 255);
raiserror('Raised #2 18', 18, 255);
go
insert into T1 (i1) values (1);
set xact_abort on; -- makes no difference
delete from T1;
Saída (mudanças de ordem):
Msg 50000, Level 16, State 1, Procedure T1_ForDelete, Line 4
Raised 16
Msg 50000, Level 16, State 255, Procedure T1_ForDelete, Line 6
Raised #2 16
(1 row(s) affected)
Msg 50000, Level 18, State 1, Procedure T1_ForDelete, Line 5
Raised 18
Msg 50000, Level 18, State 255, Procedure T1_ForDelete, Line 7
Raised #2 18
Então
select * from T1; -- Returns no records
Este é o comportamento esperado ou existe uma maneira de evitar a exclusão em caso de erro (por exemplo, gravidade/estado diferente)?
Não posso usar um "em vez de excluir" porque "on delete cascade" é empregado. Criar gatilho (MSDN), pesquisar "Em vez de"
Para que funcione como você codificou acima, você precisa de um rollback após o seu
RAISERROR
ou, como os comentários afirmam corretamente, agrupar em um TRY/CATCH.Por si só, não será tratado da mesma forma que uma declaração real ou um erro de finalização de lote. Por exemplo, isso funcionará da maneira que você espera:
No código acima, o gatilho apresentará um erro e fará com que a transação de exclusão (externa) seja revertida. Por si só, RAISERROR está apenas realmente transferindo o controle e/ou enviando mensagens para cima da pilha (por assim dizer)
BOL descreve esse comportamento:
Portanto, RAISERROR fora do escopo de um bloco TRY simplesmente retorna o erro ao chamador e não é tratado como um erro de finalização de instrução, independentemente da gravidade que você definir.