Обработка ошибок в пользовательских функциях SQL Server
Быстрый ответ
-- Если условие выполнено, вызываем ошибку, взрывающую вселенную
IF @YourCondition SELECT 1/0;
Этот код использует деление на ноль для того, чтобы вызвать ошибку внутри функции. SQL Server не позволяет использовать RAISERROR
или THROW
напрямую в пользовательских функциях. Мы успешно обходим это ограничение: ошибка деления на ноль вызывается в вызывающем коде. Для управления ошибками на высоком уровне лучше использовать хранимые процедуры.
[AsideBanner]
Управление настроенными ошибками и предотвращение путаницы
-- Создание пользовательской функции (UDF) с обработкой ошибок
CREATE FUNCTION dbo.CustomErrorExample(@InputParam INT)
RETURNS INT
AS
BEGIN
IF @InputParam IS NULL
RETURN CAST('Если данные отсутствуют, я вызову ошибку' AS INT); -- Ошибка из-за отсутствия значения
-- В этом месте выполняется пользовательская функция
RETURN @Result; -- Возвращаем результат, следуя этикету
END;
Предложенный метод позволяет обнаружить ошибку, когда входные данные некорректны. Вместо возврата NULL функция возвращает тип INT, создавая таким образом иллюзию для сервера. Когда сервер SQL пытается обработать это как целое число, срабатывает ошибка приведения типов и наша контрманевра оказывается раскрытой.
Ностальгические воспоминания об обработке ошибок в SQL Server 2008
Вспомним на минутку, как обрабатывались ошибки в SQL Server 2008.
-- Напоминание о старых добрых практиках SQL Server 2008
CREATE FUNCTION dbo.LegacyErrorSignal(@InputParam INT)
RETURNS INT
AS
BEGIN
IF @InputParam < 0
SELECT 1/0; -- Преобразуем отрицательное значение в ошибку
-- Здесь выполняется логика функции
RETURN @Result; -- Ожидаем возвратить результат, правда же?
END;
Здесь деление на ноль используется как экстренный сигнал ошибки. Этот метод следует использовать осторожно и документировать каждый его экземпляр. Документирование кода помогает будущим разработчикам понять логику.
Табличные функции с возвращением значений (TVF) и искусство управления ошибками
В мире TVF непосредственные сообщения об ошибках — большая редкость, но у нас есть способ обойти это.
-- TVF с явной отчетностью об ошибках
CREATE FUNCTION dbo.ErrorReportingTVF(@InputParam INT)
RETURNS @ResultTable TABLE
(
Result INT,
ErrorFlag BIT,
ErrorMessage VARCHAR(255)
)
AS
BEGIN
IF @InputParam IS NULL
BEGIN
INSERT INTO @ResultTable (Result, ErrorFlag, ErrorMessage)
VALUES (NULL, 1, 'В качестве входных данных получен NULL!');
RETURN;
END
-- Здесь происходит обработка TVF
-- Заполняем набор результатов, потому что к каждому нужно относиться на равных
INSERT INTO @ResultTable (Result, ErrorFlag, ErrorMessage)
VALUES (@CalculatedResult, 0, NULL);
RETURN;
END;
Функции TVF возвращают результирующий набор с полями ErrorFlag
и ErrorMessage
, которые служат для указания на ошибки.
Визуализация
В SQL Server пользовательские функции (UDF) работают как изолированные блоки, процессируя записи в наборах данных. Несмотря на изолированность, UDF способны сообщать об ошибках не нарушая ограничений функций.
UDF заявляют: "Я справлюсь самостоятельно. Поднимать флаги не буду!"
Но если в функции возникает проблема, она уведомит об этом:
UDF подсказывают: "Следуйте инструкциям."
А в инструкциях всегда указано, как распознать аномалию:
UDF заявляют: "Каждый результат тщательно проверен."
И если вызывающая сторона получит сообщение об ошибке:
Вызывающий код предупреждает: "При обнаружении ошибки будут подняты красные флаги."
Таким образом, UDF ясно информируют о возникающих проблемах.
Мудрый совет: валидируйте входные данные, чтобы предотвратить ошибки
Некорректные входные данные в UDF могут вызвать проблемы. Для предотвращения распространённых ошибок внимательно обрабатывайте данные. Нестандартные сообщения об ошибках могут помочь в поиске и исправлении проблем.
Откажитесь от 'Таинственного Режима': Сделайте поведение функции ясным
Документируйте специфическое поведение функций, чтобы другие разработчики понимали ожидаемые результаты и причины возможного возврата NULL.
Обеспечьте комфорт разработчика: упростите диагностику NULL
Создайте лучший опыт для разработчиков, предоставляя контекстную обработку ошибок, которая поможет лучше понять причины возникновения результатов в виде NULL.
Попробуйте альтернативные стратегии сообщения об ошибках, отличные от деления на ноль
Деление на ноль — хитрый приём, но есть и другие методы обработки ошибок. Например, настройка возвращаемых значений, условные сообщения об ошибках или даже TVF, созданные специально для обработки ошибок.
Полезные материалы
- CREATE FUNCTION (Transact-SQL) – SQL Server | Microsoft Learn — официальная документация по созданию пользовательских функций SQL Server.
- TRY...CATCH (Transact-SQL) – SQL Server | Microsoft Learn — подробности обработки ошибок с помощью TRY...CATCH в Transact-SQL.
- sql server – Get ticket sales and reservations grouped by time slot – Database Administrators Stack Exchange — полезные обсуждения о пользовательских функциях SQL Server.
- SQL Server Script to Determine Free Space Prior to SQL Server Backup — статья с примерами сообщения об ошибках в UDF SQL Server.
- Windows File Share – SQL Server Forums — дискуссии на форуме о сообщении об ошибках в пользовательских функциях SQL Server.