З документації RAISERROR (міна акценту):
Рівень тяжкості від 0 до 18 може визначати будь-який користувач. Рівні ступеня вираженості від 19 до 25 можуть визначати лише члени ролі фіксованого сервера sysadmin або користувачі з дозволом ALTER TRACE. Для рівнів тяжкості від 19 до 25 потрібен варіант ЗНО ЛОГ.
Цілком ймовірно, що головний, який ви виконуєте сценарій, не відповідає цим критеріям.
У використанні немає нічого поганого RAISERROR
; ви просто використовуєте надмірний ступінь вираженості. Я використовую рівень 16 за замовчуванням для помилки, яка піднімається, і послідовність буде припинена. Якщо ви хочете бути більш точними, ви можете дотримуватися рівнів, заданих самим Microsoft:
Тепер, сказавши все це, залежно від контексту сценарію, використання RAISERROR
може бути недостатньо, оскільки він не "виходить" з сценарію сам (використовуючи нормальний рівень вираженості).
Наприклад:
RAISERROR(N'Test', 16, 1);
SELECT 1; /* Executed! */
Це і викличе помилку і повертає набір результатів.
Для негайного припинення роботи сценарію я вважаю за краще використовувати RETURN
(використання GOTO
конструкцій типу, як правило, не рекомендується в більшості програмних кіл, де існують альтернативи):
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
метод, якщо це підходить для вашого оточення.