2

我想知道是否有更好的方法将 Varchar 解析为 TSQL / SQL Server 中的 Int。我说“解析”是因为我需要比 CAST/CONVERT 系统功能更强大的东西;当解析失败时返回 NULL 甚至是“默认”值特别有用。

所以这是我现在使用的函数,最初是从某人的SQL博客中获得的(甚至不记得具体是谁)......

更改功能 [dbo].[udf_ToNumber]
(
    @Str varchar(最大值)
)
返回整数
作为
开始
    声明@Result int

    SET @Str = LTRIM(RTRIM(@Str))

    IF (@Str='' 或 @Str 为空
        或 ISNUMERIC(@Str)=0
        或 @Str LIKE '%[^-+ 0-9]%'
        或 @Str IN ('.', '-', '+', '^')
        )
        SET @Result = NULL
    别的
    IF (CAST(@Str AS NUMERIC(38,0)) 不在 -2147483648 和 2147483647 之间。)
        SET @Result = NULL
    别的
        SET @Result = CAST(@Str AS int)

    返回@结果
结尾

(并且您可以在末尾添加一行,例如“如果@Result 为空,则设置@Result =”或类似的内容)。

这不是很有效,因为在 JOIN 或 WHERE-IN-SELECT 中使用它——比如 LEFT 列是 INT,RIGHT 是 VARCHAR,我尝试解析 RIGHT——在任何非常大的数据集上,都需要比我先将 LEFT (INT) 列转换为 VARCHAR 然后执行 JOIN 长得多。

无论如何,我“理想地”知道,如果我的表/数据类型被适当地创建和填充,我首先不需要做这种事情,但我们都知道理想世界有时与现实相去甚远,所以幽默我。谢谢!

编辑:SQL Server 2005 和 2008 版;运行 2005 的盒子将很快升级,因此 2008 特定的答案很好。

4

1 回答 1

2

以我的经验,标量 udf 在较大的数据集上表现不佳;作为一种解决方法,您可以尝试以下两个选项之一(我不确定它们中的任何一个是否会特别好):

  1. 将函数的逻辑嵌入到 join 本身中,如下所示:

    SELECT columnlist
    FROM a JOIN b ON a.INT = (SELECT  CASE WHEN ( b.varchar= ''
                        OR b.varchar IS NULL
                        OR ISNUMERIC(b.varchar) = 0
                        OR b.varchar LIKE '%[^-+ 0-9]%'
                        OR b.varchar IN ( '.', '-', '+', '^' )
                      ) THEN NULL
                 WHEN CAST(b.varchar AS NUMERIC(38, 0)) NOT BETWEEN -2147483648.
                                                   AND         2147483647.
                 THEN NULL
                 ELSE CAST (b.varchar AS INT)
            END)
    
  2. 将您的用户定义函数更改为内联表值函数并使用 CROSS APPLY 语法:

    CREATE FUNCTION udf_ToInt
    (   
        @str VARCHAR(MAX)
    )
    RETURNS TABLE 
    AS
    RETURN 
    (
        SELECT  CASE WHEN ( @Str = ''
                        OR @Str IS NULL
                        OR ISNUMERIC(@Str) = 0
                        OR @Str LIKE '%[^-+ 0-9]%'
                        OR @Str IN ( '.', '-', '+', '^' )
                      ) THEN NULL
                 WHEN CAST(@Str AS NUMERIC(38, 0)) NOT BETWEEN -2147483648.
                                                   AND         2147483647.
                 THEN NULL
                 ELSE CAST (@Str AS INT) as IntVal
            END           
    
    )
    GO
    
    SELECT columnlist
    FROM b
    CROSS APPLY udf_ToInt(b.varchar) t
    JOIN a ON t.IntVal = a.Int
    

可能更容易转换为 VARCHAR 并进行比较:)

于 2012-06-21T17:40:57.423 回答