我想知道在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年的具体答案很好。
答案 0 :(得分:2)
根据我的经验,标量udf在较大的数据集上表现不佳;作为一种解决方法,你可以尝试两种选择之一(我不确定它们中的任何一种都能很好地工作):
将函数的逻辑嵌入到连接本身中,如下所示:
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)
将用户定义的函数更改为内联表值函数,并使用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并进行比较:)