powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / непонятное поведение триггера
3 сообщений из 3, страница 1 из 1
непонятное поведение триггера
    #32075302
sim
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
sim
Гость
Извините за длинный пост, так получилось :(
Итак,
фрагмент кода триггера на insert таблицы TABLE2 (в угловых скобках номер строки):
...
<12>/*
<13> * PREVENT NULL VALUES IN 'FIELD1'
<14> */
<15>IF (SELECT Count(*) FROM inserted WHERE FIELD1 IS NULL) > 0
<16> BEGIN
<17> RAISERROR 44444 'Field ''FIELD1'' cannot contain a null value.'
<18> ROLLBACK TRANSACTION
<19> END
<20>/*
<21> * PREVENT INSERTS IF NO MATCHING KEY IN 'TABLE1'
<22> */
<23>IF (SELECT COUNT(*) FROM inserted) !=
<24> (SELECT COUNT(*) FROM TABLE1, inserted WHERE (TABLE1.FIELD2 = inserted.FIELD2))
<25> BEGIN
<26> RAISERROR(779025, 16, 1)
<27> ROLLBACK TRANSACTION
<28> END
...

вот фрагмент кода процедуры:
...
BEGIN
BEGIN TRANSACTION
INSERT INTO DBO.TABLE1 (FIELD1)
VALUES (123)
INSERT INTO DBO.TABLE2 (FIELD1, FIELD2) VALUES (123, @PARAM1)
COMMIT TRANSACTION
SELECT @RETURN_CODE = FIELD2 FROM DBO.TABLE1 WHERE FIELD1 = 123
IF @RETURN_CODE IS NULL
-- ошибка вставки
SET @RETURN_CODE = -6
END
...

вот код, вызываемый в QA:
DECLARE @C INT
EXEC .SP_MY_PROCEDURE @C OUTPUT, NULL -- @PARAM1 = NULL, т.е. попытка вставить NULL в not nullable-поле
SELECT @C
GO

вот что возвращается после выполнения кода:
Server: Msg 3903, Level 16, State 1, Procedure TABLE2_ITrig, Line 27
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
Server: Msg 44444, Level 16, State 1, Procedure TABLE2_ITrig, Line 17
Field 'FIELD1' cannot contain a null value.
Server: Msg 779025, Level 16, State 1, Procedure TABLE2_ITrig, Line 26
Cannot add or change record. Referential integrity rules require a related record in table ''TABLE1''.
The statement has been terminated.

т.е. происходит следующее:
в процедуре выполняется 2-й insert в транзакции (1-й проходит успешно, как и задумано), срабатывает триггер,
проверка (строки 12-19) не проходит, рейзится ошибка (строка 17), происходит роллбэк до начала транзакции в процедуре.
Триггер продолжает выполняться, рейзится 2-я ошибка (строка 26), т.к. 1-й роллбэк откатил данные 1-го инсерта,
затем попытка выполнить роллбэк уже несуществующей транзакции (строка 27).
Таким образом, все стройно и логично :)
Но...
Во-первых, смущает порядок рейзания ошибок - сначала на 27-й, потом на 17-й и в конце на 26-й строке.
Во-вторых, почему 2 первых ошибки не приводят к завершению триггера, а только 3-я (уровень грубости у всех одинаковый)?
В-третьих, триггер завершает работу процедуры, чего хотелось бы избежать...
...
Рейтинг: 0 / 0
непонятное поведение триггера
    #32075317
DmitryV
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет!
Сдается мне, что сначала вывелась системная ошибка, а потом пользовательские в порядке поступления (см. номера ошибок).
Перед откатом можно (нужно?) проверять наличие транзакции :-)) (@@TranCount).

Удачи
...
Рейтинг: 0 / 0
непонятное поведение триггера
    #32075341
Glory
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
If a ROLLBACK TRANSACTION is issued in a trigger:

1. All data modifications made to that point in the current transaction are rolled back, including any made by the trigger.

2. The trigger continues executing any remaining statements after the ROLLBACK statement. If any of these statements modify data, the modifications are not rolled back. No nested triggers are fired by the execution of these remaining statements.

3. The statements in the batch after the statement that fired the trigger are not executed.

So if the trigger continues executing after the RAISERROR 44444 ROLLBACK TRANSACTION (see p.2)
and executes IF (SELECT COUNT(*) FROM inserted) !=
<24> (SELECT COUNT(*) FROM TABLE1, inserted WHERE (TABLE1.FIELD2 = inserted.FIELD2)) which generate True because there are no already inserted data in TABLE1 (see p.1) and you receive RAISERROR(779025, 16, 1). A then you try rollback transaction one more time but there is no active transaction and server generates error message 3903.
...
Рейтинг: 0 / 0
3 сообщений из 3, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / непонятное поведение триггера
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]