3

如果可转换,我有以下函数将字符串转换为 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 (RTM) - 15.0.2000.5 (X64) Sep 24 2019 13:48:23 版权所有 (C) 2019 Microsoft Corporation Developer Edition (64-bit) o​​n Windows 10 Pro 10.0 (Build 18362:) (Hypervisor)

如果它不是数字,return 语句停止返回 null 值。因此我开始收到以下错误:

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

我必须在If 条件之外添加一个 return 语句才能从函数中返回任何值。我怎样才能解决这个问题?

在此处输入图像描述

4

1 回答 1

4

这是 SQL Server 2019 中标量 UDF 内联的错误。

执行计划如下

在此处输入图像描述

传递给函数的值是从右上角的常量扫描发出的,并别名为 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 

在输入不是远程数字的情况下,无论CASE表达式最终采用哪条路径,这都会爆炸。

该问题与此处的问题相似。绿色突出显示的常量扫描位于带有传递谓词的内部连接下,因此只有在ISNUMERIC测试为真时才会评估。该常量扫描的输出列表是空的,所以我假设表达式可能从那里移动,并且与链接的答案具有相同的错误逻辑。

您可以使用WITH INLINE = OFF关闭该函数的内联,但可能您应该完全删除它并替换为TRY_CONVERT(或者如果此时无法完全删除它,至少替换函数的主体)

于 2020-04-10T17:25:44.123 回答