Оператор возврата внутри Если условие не работает в SQL Функции - PullRequest
2 голосов
/ 08 апреля 2020

У меня есть следующая функция для преобразования строки в int, если она конвертируема:

CREATE FUNCTION dbo.[Dyve_FN_TryConvertInt](@Value varchar(18))
RETURNS int
AS
BEGIN
    SET @Value = REPLACE(@Value, ',', '')
    IF ISNUMERIC(@Value + 'e0') = 0 RETURN NULL
    IF ( CHARINDEX('.', @Value) > 0 AND CONVERT(bigint, PARSENAME(@Value, 1)) <> 0 ) RETURN NULL
    DECLARE @I bigint =
        CASE
        WHEN CHARINDEX('.', @Value) > 0 THEN CONVERT(bigint, PARSENAME(@Value, 2))
        ELSE CONVERT(bigint, @Value)
        END
    IF ABS(@I) > 2147483647 RETURN NULL
    RETURN @I
END
GO

Она работала до и после обновления до следующей версии

Microsoft SQL Server 2019 (Окончательная первоначальная версия) - 15.0.2000.5 (X64) 24 сентября 2019 г. 13:48:23 Авторское право (C) Издание Microsoft Corporation для разработчиков (64-разрядная версия) 2019 г. на Windows 10 Pro 10.0 (сборка 18362:) (гипервизор)

Оператор возврата прекратил возвращать нулевое значение, если оно не числовое c. Поэтому я начал получать следующую ошибку:

Msg 8114, Level 16, State 5, Line 1 Error converting data type varchar
 to bigint.

Я должен добавить инструкцию возврата вне Если условие чтобы вернуть любое значение из функции. Как я могу это исправить?

enter image description here

1 Ответ

3 голосов
/ 10 апреля 2020

Это ошибка с встраиванием скалярных пользовательских функций в SQL Сервер 2019.

План выполнения выглядит следующим образом

enter image description here

Значение, переданное функции, выводится из константы сканирования в правом верхнем углу и имеет псевдоним Expr1000. Это передается до тех пор, пока, в конце концов, оно не попадет в вычисляемый скаляр, содержащий следующее выражение

[Expr1007]=CASE
           WHEN CHARINDEX('.', [Expr1000]) > ( 0 )
             THEN CONVERT(BIGINT, PARSENAME(CONVERT_IMPLICIT(nvarchar(18), [Expr1000], 0), ( 2 )), 0)
           ELSE CONVERT(BIGINT, [Expr1000], 0)
         END 

В случае, если вход не является удаленным числом c, это взорвется независимо от того, по какому пути CASE выражение в конечном итоге принимает.

Проблема выглядит как здесь . Постоянное сканирование, выделенное зеленым цветом, находится во внутреннем соединении с предикатом сквозного прохождения, поэтому будет оцениваться только в том случае, если тест ISNUMERIC был истинным. Список вывода для этого постоянного сканирования пуст, поэтому я предполагаю, что, скорее всего, выражение было перемещено оттуда с теми же ошибочными логами c, что и для связанного ответа.

Вы можете использовать WITH INLINE = OFF, чтобы отключить встраивание для эту функцию, но, скорее всего, вам следует просто полностью удалить ее и заменить на TRY_CONVERT (или хотя бы заменить тело функции на это, если невозможно удалить ее полностью в это время)

...