RAISERROR: примеры (SQL)
RAISERROR: intФункция RAISERROR в MS SQL
Функция RAISERROR в Microsoft SQL Server предназначена для генерации пользовательских сообщений об ошибках и передачи управления обработчику ошибок. Использование функции происходит в сценариях валидации данных, обработки бизнес-логики или для сигнализации о состоянии выполнения пакетов и процедур.
Синтаксис функции включает следующие аргументы:
RAISERROR ( { msg_id | msg_str | @local_variable }
{ , severity , state }
[ , argument [ , ...n ] ] )
[ WITH option [ , ...n ] ]- msg_id: Уникальный идентификатор пользовательской ошибки, зарегистрированный в системном представлении sys.messages. Должен быть больше или равен 50000.
- msg_str: Строка сообщения, схожая с функцией printf в языке C. Может содержать заполнители для аргументов.
- @local_variable: Переменная, содержащая строку сообщения.
- severity: Уровень серьезности ошибки от 0 до 25. Пользовательские уровни обычно находятся в диапазоне 11-20. Уровни 20-25 считаются фатальными и требуют указания параметра WITH LOG.
- state: Целое число от 1 до 255, обозначающее состояние ошибки. Используется для идентификации места возникновения ошибки в коде.
- argument: Параметры, подставляемые в заполнители строки сообщения. Допускается до 20 аргументов.
- WITH option: Дополнительные параметры:
- WITH LOG — запись ошибки в журнал приложения и журнал ошибок SQL Server.
- WITH NOWAIT — немедленная отправка сообщения клиенту.
- WITH SETERROR — установка значения @@ERROR равным указанному msg_id или 50000.
Функция не возвращает значения в традиционном понимании, но влияет на системные функции @@ERROR и вызывает выполнение блока CATCH при использовании в конструкции TRY...CATCH.
Простые примеры использования
Пример с пользовательским текстом сообщения и уровнем серьезности 16:
RAISERROR ('Нарушение бизнес-правила', 16, 1);Сообщение 50000, уровень 16, состояние 1, строка 1
Нарушение бизнес-правила
Использование форматирования строки с аргументами:
DECLARE @ProductName NVARCHAR(50) = N'Молоко';
DECLARE @MinQuantity INT = 10;
RAISERROR (N'Товар \"%s\" остался в количестве меньше %d единиц', 10, 1, @ProductName, @MinQuantity);
Сообщение 50000, уровень 10, состояние 1, строка 3
Товар "Молоко" остался в количестве меньше 10 единиц
Использование зарегистрированного пользовательского сообщения:
EXEC sp_addmessage @msgnum = 50005, @severity = 16,
@msgtext = N'Недействительное значение параметра: %s', @lang = 'русский';
RAISERROR (50005, 16, 1, N'ID пользователя');
Сообщение 50005, уровень 16, состояние 1, строка 2
Недействительное значение параметра: ID пользователя
Пример с параметром WITH LOG:
RAISERROR ('Критическая ошибка конфигурации', 22, 1) WITH LOG;Сообщение 50000, уровень 22, состояние 1, строка 1
Критическая ошибка конфигурации
// Сообщение также записывается в журнал ошибок SQL Server
Альтернативные механизмы в MS SQL
THROW — инструкция, появившаяся в SQL Server 2012. Она имеет более простой синтаксис: THROW [ error_number, message, state ]. В отличие от RAISERROR, THROW всегда устанавливает уровень серьезности 16. Инструкция THROW требует указания существующего номера ошибки или 50000. THROW может быть использована без параметров для повторного вызова пойманной ошибки в блоке CATCH.
PRINT — инструкция для вывода информационных сообщений клиенту с уровнем серьезности 0. Она не вызывает ошибку и не передает управление блоку CATCH.
Выбор между RAISERROR и THROW зависит от задачи. THROW предпочтительнее для современных проектов из-за соответствия стандарту SQL и более простого синтаксиса. RAISERROR предоставляет больше контроля над уровнем серьезности и возможностями форматирования, а также поддерживает отправку сообщений в журнал событий.
Аналоги в других СУБД и языках
MySQL: Используется инструкция SIGNAL. Она позволяет указывать SQLSTATE, значение ошибки и сообщение.
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Пользовательская ошибка';
# Возникает ошибка с заданным SQLSTATE и текстом
Oracle: Применяется процедура RAISE_APPLICATION_ERROR в пакете DBMS_STANDARD.
RAISE_APPLICATION_ERROR(-20001, 'Недействительная операция');
ORA-20001: Недействительная операция
PostgreSQL: Для вызова исключений используются инструкции RAISE EXCEPTION или RAISE.
RAISE EXCEPTION 'Ошибка данных: %', 'неверный формат' USING HINT = 'Проверьте ввод';
ERROR: Ошибка данных: неверный формат
HINT: Проверьте ввод
SQLite: Нет встроенной функции для пользовательских ошибок. Обычно используется возврат кодов ошибок или вызов исключений на уровне приложения.
Sybase ASE: Поддерживает функцию RAISERROR с синтаксисом, очень похожим на MS SQL.
Языки программирования: В большинстве языков используются конструкции throw new Exception() (C#, Java) или raise (Python). Они, как правило, интегрированы в объектно-ориентированную модель исключений, в отличие от SQL-подхода.
Частые ошибки при применении
Использование несуществующего номера сообщения без предварительной регистрации через sp_addmessage приводит к ошибке.
RAISERROR (60000, 16, 1);
Сообщение 18054, уровень 16, состояние 1, строка 1
Ошибка 60000, уровень 16, состояние 1 не определена. Ошибку следует определять, начиная с 50000.
Указание уровня серьезности 20-25 без параметра WITH LOG вызывает ошибку.
RAISERROR ('Фатальная ошибка', 21, 1);Сообщение 2745, уровень 16, состояние 2, строка 1
Для ошибок уровня серьезности 20 и выше параметр WITH LOG является обязательным.
Передача аргументов, не соответствующих заполнителям в строке, может приводить к некорректному выводу или ошибке.
RAISERROR ('Значение: %s, %d', 10, 1, 'Текст');
-- Передан только один аргумент вместо двухСообщение 50000, уровень 10, состояние 1, строка 1
Значение: Текст, 0
Обновления в новых версиях
Начиная с SQL Server 2012, корпорация Майкрософт рекомендует использовать инструкцию THROW для новой разработки. Функция RAISERROR сохраняется для обратной совместимости, но не получает значительных функциональных обновлений.
Важное изменение связано с уровнем серьезности. В SQL Server 2014 и выше, при использовании RAISERROR с уровнем серьезности от 20 до 25, сеанс завершается, если ошибка не обрабатывается в блоке TRY...CATCH. Это отличает поведение от более старых версий.
В SQL Server 2016 улучшена интеграция RAISERROR с компонентами Always On и группы доступности, но синтаксис и основные возможности остаются неизменными.
Расширенные сценарии применения
Динамическое формирование сообщения об ошибке на основе данных таблицы:
DECLARE @EmpID INT = 999;
DECLARE @ErrorMsg NVARCHAR(4000);
IF NOT EXISTS (SELECT 1 FROM Employees WHERE EmployeeID = @EmpID)
BEGIN
SET @ErrorMsg = N'Сотрудник с ID ' + CAST(@EmpID AS NVARCHAR) + N' не найден.';
RAISERROR (@ErrorMsg, 16, 1);
END
Сообщение 50000, уровень 16, состояние 1, строка 6
Сотрудник с ID 999 не найден.
Использование RAISERROR в блоке TRY...CATCH с последующей обработкой:
BEGIN TRY
RAISERROR ('Тестовая ошибка', 16, 1);
END TRY
BEGIN CATCH
PRINT 'Поймана ошибка: ' + ERROR_MESSAGE();
-- Возможно логирование или другие действия
END CATCH
Поймана ошибка: Тестовая ошибка
Пакетная обработка с накоплением ошибок и выводом итогового сообщения:
DECLARE @ErrorCount INT = 0;
-- ... выполнение операций в цикле
IF @@ERROR <> 0 SET @ErrorCount = @ErrorCount + 1;
-- ...
IF @ErrorCount > 0
RAISERROR ('Завершено с %d ошибками', 10, 1, @ErrorCount);
Сообщение 50000, уровень 10, состояние 1, строка 6
Завершено с 3 ошибками
Использование состояния (state) для идентификации места ошибки в сложной процедуре:
CREATE PROCEDURE sp_ComplexProc
AS
BEGIN
-- Блок 1
IF (1=0) -- Условие имитации ошибки
RAISERROR ('Ошибка в блоке валидации', 16, 1);
-- Блок 2
IF (1=0)
RAISERROR ('Ошибка в блоке расчета', 16, 2);
END
-- В зависимости от того, где возникла ошибка, state будет 1 или 2, что упрощает отладку.