TSQL - 更好的INT转换功能

时间:2012-06-21 16:11:25

标签: sql-server tsql type-conversion

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

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

ALTER FUNCTION [dbo].[udf_ToNumber]
(
    @Str varchar(max)
)
RETURNS int
AS
BEGIN
    DECLARE @Result int

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

    IF (@Str='' OR @Str IS NULL
        OR ISNUMERIC(@Str)=0
        OR @Str LIKE '%[^-+ 0-9]%'
        OR @Str IN ('.', '-', '+', '^') 
        )
        SET @Result = NULL
    ELSE
    IF (CAST(@Str AS NUMERIC(38,0)) NOT BETWEEN -2147483648. AND 2147483647.)
        SET @Result = NULL
    ELSE
        SET @Result = CAST(@Str AS int)

    RETURN @Result
END

(你可以在结尾前添加一行,比如“如果@Result为null,设置@Result =”,或类似的东西)。

效率不高,因为在JOIN或WHERE-IN-SELECT中使用它 - 其中LEFT列是INT而RIGHT是VARCHAR,我尝试解析RIGHT - 对任何非常大的数据 - set,比我先将LEFT(INT)列CAST到VARCHAR然后再进行JOIN需要更长的时间。

无论如何,我知道'理想'我不应该首先做这种事情,如果我的表格/数据类型被创建&适当填充,但我们都知道理想世界有时候离现实很远,所以幽默我。谢谢!

编辑:SQL Server版本2005& 2008;运行2005年的盒子将很快升级,因此2008年的具体答案很好。

1 个答案:

答案 0 :(得分:2)

根据我的经验,标量udf在较大的数据集上表现不佳;作为一种解决方法,你可以尝试两种选择之一(我不确定它们中的任何一种都能很好地工作):

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

    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
    
  3. 可能更容易转换为VARCHAR并进行比较:)