THROW: примеры (SQL)
THROW(error_number, message, state): N/AФункция THROW в MS SQL Server
Функция THROW используется для генерации пользовательских исключений и передачи управления блоку CATCH в конструкции TRY...CATCH. Эта функция доступна начиная с SQL Server 2012.
Функция применяется в ситуациях, когда требуется прервать выполнение пакета или процедуры из-за нарушенного бизнес-правила, недопустимого состояния данных или других ошибок логики приложения. Её вызов приводит к возврату управления в блок CATCH или завершению выполнения, если блока CATCH нет.
Синтаксис:
THROW [ { error_number | @local_variable },
{ message | @local_variable },
{ state | @local_variable }
] [ ; ]Аргументы:
- error_number — целочисленная константа или переменная, представляющая номер исключения. Допустимый диапазон от 50000 до 2147483647. Номера, меньшие 50000, зарезервированы системой SQL Server.
- message — строка nvarchar(2048), описывающая причину исключения.
- state — tinyint (от 0 до 255) или переменная, указывающая состояние ошибки. Значение 0 по умолчанию.
Возвращаемое значение: Функция THROW не возвращает значение. Её выполнение всегда приводит к разрыву потока выполнения.
Особенности: Если параметр error_number равен NULL, используется номер ошибки 50000. Если message равен NULL, используется текст последней ошибки, сгенерированной в сеансе. Если блок CATCH отсутствует, сеанс прерывается.
Примеры использования THROW
Базовый вызов с указанием всех параметров:
THROW 51000, 'Нарушено бизнес-правило: сумма не может быть отрицательной.', 1;Сообщение 51000, уровень 16, состояние 1, строка 1
Нарушено бизнес-правило: сумма не может быть отрицательной.
Использование переменных для передачи параметров:
DECLARE @ErrorNumber INT = 50001,
@ErrorMessage NVARCHAR(2048) = N'Ошибка валидации данных',
@ErrorState TINYINT = 10;
THROW @ErrorNumber, @ErrorMessage, @ErrorState;Сообщение 50001, уровень 16, состояние 10, строка 4
Ошибка валидации данных.
Повторное возбуждение исходной ошибки внутри блока CATCH без параметров:
BEGIN TRY
SELECT 1/0;
END TRY
BEGIN CATCH
PRINT 'Произошла ошибка, повторно возбуждаю её.';
THROW;
END CATCHПроизошла ошибка, повторно возбуждаю её.
Сообщение 8134, уровень 16, состояние 1, строка 2
Обнаружено деление на ноль.
Похожие функции в MS SQL Server
RAISERROR — устаревшая функция для генерации пользовательских сообщений об ошибках. Поддерживает форматирование через аргументы, подобное функции printf. В отличие от THROW, RAISERROR может генерировать ошибки с уровнем серьёзности от 0 до 25, но не всегда прерывает выполнение пакета. Для новых разработок рекомендуется использовать THROW.
TRY...CATCH — не функция, а конструкция языка для обработки исключений. THROW обычно используется внутри неё для явного возбуждения ошибок. Конструкция обеспечивает перехват и обработку исключений.
Альтернативы в других системах
MySQL: Используется конструкция SIGNAL. Позволяет указать SQLSTATE, сообщение и различные атрибуты ошибки.
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Пользовательская ошибка';ERROR 1644 (45000): Пользовательская ошибка
PostgreSQL: Применяется команда RAISE с указанием уровня (DEBUG, LOG, INFO, NOTICE, WARNING, EXCEPTION).
RAISE EXCEPTION 'Ошибка проверки %', 'данных' USING ERRCODE = 'P0001';ERROR: Ошибка проверки данных
Oracle: Используется RAISE_APPLICATION_ERROR в составе PL/SQL. Позволяет задать номер ошибки (от -20000 до -20999) и сообщение.
RAISE_APPLICATION_ERROR(-20001, 'Недопустимое значение параметра');ORA-20001: Недопустимое значение параметра
Типичные ошибки при работе с THROW
Вызов THROW без параметров вне блока CATCH приводит к ошибке.
THROW;Сообщение 10704, уровень 15, состояние 1, строка 1
Для использования THROW без параметров инструкция должна находиться внутри блока CATCH.
Использование номера ошибки вне допустимого диапазона.
THROW 49999, 'Тест', 1;Сообщение 35100, уровень 16, состояние 10, строка 1
Номер ошибки в инструкции THROW должен быть больше или равен 50000 и меньше или равен 2147483647.
Пропуск точки с запятой перед инструкцией THROW в некоторых контекстах может вызвать синтаксическую ошибку.
BEGIN
PRINT 'Test'
THROW 50000, 'Error', 1
ENDСообщение 102, уровень 15, состояние 1, строка 3
Синтаксическая ошибка около 'THROW'.
Изменения в последних версиях
В SQL Server 2017 и более новых версиях не было внесено существенных изменений в синтаксис или поведение функции THROW. Основные возможности были представлены в версии 2012, где функция появилась. Рекомендуется следить за официальной документацией на случай появления новых возможностей.
Расширенные примеры применения THROW
Использование в хранимой процедуре для валидации входных параметров с последующей логической обработкой в CATCH.
CREATE PROCEDURE UpdateBalance @AccountId INT, @Delta DECIMAL(10,2)
AS
BEGIN
IF @Delta < 0
THROW 51000, 'Изменение баланса не может быть отрицательным', 1;
-- Основная логика
PRINT 'Баланс обновлён.';
END
BEGIN TRY
EXEC UpdateBalance 1, -100;
END TRY
BEGIN CATCH
PRINT 'Ошибка: ' + ERROR_MESSAGE();
-- Логирование или откат транзакции
END CATCHОшибка: Изменение баланса не может быть отрицательным
Каскадное возбуждение ошибок с разными состояниями для отладки сложных сценариев.
BEGIN TRY
BEGIN TRY
THROW 50001, 'Внутренняя ошибка', 5;
END TRY
BEGIN CATCH
PRINT 'Внутренний блок перехватил ошибку с состоянием: ' + CAST(ERROR_STATE() AS NVARCHAR);
THROW 50002, 'Внешняя ошибка после обработки', 10;
END CATCH
END TRY
BEGIN CATCH
PRINT 'Внешний блок перехватил ошибку с состоянием: ' + CAST(ERROR_STATE() AS NVARCHAR);
PRINT 'Сообщение: ' + ERROR_MESSAGE();
END CATCHВнутренний блок перехватил ошибку с состоянием: 5
Внешний блок перехватил ошибку с состоянием: 10
Сообщение: Внешняя ошибка после обработки
Комбинирование THROW и XACT_STATE для управления транзакциями в распределённых сценариях.
BEGIN TRY
BEGIN TRAN;
-- Некоторая операция
IF @@TRANCOUNT > 0 AND XACT_STATE() = 1
ROLLBACK TRAN;
THROW 60000, 'Ошибка с откатом транзакции', 1;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 AND XACT_STATE() = 1
ROLLBACK TRAN;
THROW;
END CATCHСообщение 60000, уровень 16, состояние 1, строка 8
Ошибка с откатом транзакции