Из документации RAISERROR (выделено мое):
Уровни серьезности от 0 до 18 могут быть указаны любым пользователем. Уровни серьезности от 19 до 25 могут указываться только членами предопределенной роли сервера sysadmin или пользователями с разрешениями ALTER TRACE. Для уровней серьезности от 19 до 25 требуется опция WITH LOG.
Весьма вероятно, что основной пользователь, которого вы выполняете сценарий, не соответствует этим критериям.
Там нет ничего плохого в использовании RAISERROR
; вы просто используете уровень серьезности, который является чрезмерным. Я использую уровень 16 по умолчанию для ошибки, которая возникает, и последовательность будет прервана. Если вы хотите быть более точным, вы можете следовать уровням, данным самой Microsoft:
Теперь, сказав все это, в зависимости от контекста сценария, используя RAISERROR
может быть недостаточным, так как он не «сам по себе» выходит из сценария (используя нормальные уровни серьезности).
Например:
RAISERROR(N'Test', 16, 1);
SELECT 1; /* Executed! */
Это и вызовет ошибку и возвращает набор результатов.
Для немедленного завершения сценария я предпочитаю использовать RETURN
(использование GOTO
конструкций -type обычно не рекомендуется в большинстве кругов программирования, где существуют альтернативы):
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
Или обработайте ошибку, используя TRY/CATCH
, что вызовет переход к CATCH
блоку, если уровень серьезности равен 11 или выше:
BEGIN TRY
RAISERROR(N'Test', 16, 1);
SELECT 1; /* Not executed */
END TRY
BEGIN CATCH
SELECT 2; /* Executed */
END CATCH
BEGIN TRY
RAISERROR(N'Test', 10, 1);
SELECT 1; /* Executed */
END TRY
BEGIN CATCH
SELECT 2; /* Not executed */
END CATCH
Отдельная проблема заключается в том, что если сценарий охватывает несколько пакетов, он RETURN
будет выходить только из пакета :
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
GO
SELECT 2; /* Executed! */
Чтобы это исправить, вы можете проверить @@ERROR
в начале каждой партии:
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
GO
IF (@@ERROR != 0)
RETURN;
SELECT 2; /* Not executed */
Изменить: как правильно указывает Мартин Смит в комментариях, это работает только для 2 партий. Чтобы расширить до 3 или более пакетов, вы можете каскадно создавать ошибки, например, так (примечание: GOTO
метод не решает эту проблему, так как метка назначения должна быть определена в пакете):
RAISERROR(N'Test', 16, 1);
RETURN;
SELECT 1; /* Not executed */
GO
IF (@@ERROR != 0)
BEGIN
RAISERROR(N'Error already raised. See previous errors.', 16, 1);
RETURN;
END
SELECT 2; /* Not executed */
GO
IF (@@ERROR != 0)
BEGIN
RAISERROR(N'Error already raised. See previous errors.', 16, 1);
RETURN;
END
SELECT 3; /* Not executed */
Или, как он также указывает, вы можете использовать SQLCMD
метод, если он подходит для вашей среды.