SQL Server 2012及之后版本
只需使用Try_Convert
函数即可:
TRY_CONVERT将传递给它的值尝试转换为指定的数据类型。如果转换成功,TRY_CONVERT将该值作为指定的数据类型返回;如果出现错误,则返回null。但是,如果您请求明确不允许的转换,则TRY_CONVERT会失败并显示错误。
了解更多关于Try_Convert的内容。
SQL Server 2008及之前版本
传统的处理方式是用CASE语句保护每个表达式,以便无论何时对其进行评估,都不会创建错误,即使在逻辑上看来不需要CASE语句也是如此。像这样:
SELECT
Account_Code =
Convert(
bigint,
CASE
WHEN X.Account_Code LIKE '%[^0-9]%' THEN NULL
ELSE X.Account_Code
END
),
A.Descr
FROM dbo.Account A
WHERE
Convert(
bigint,
CASE
WHEN X.Account_Code LIKE '%[^0-9]%' THEN NULL
ELSE X.Account_Code
END
) BETWEEN 503100 AND 503205
不过,我喜欢在使用SQL Server 2005及以上版本时采用这样的策略:
SELECT
Account_Code = Convert(bigint, X.Account_Code),
A.Descr
FROM
dbo.Account A
OUTER APPLY (
SELECT A.Account_Code WHERE A.Account_Code NOT LIKE '%[^0-9]%'
) X
WHERE
Convert(bigint, X.Account_Code) BETWEEN 503100 AND 503205
这个操作的作用是在
X
表中,当
Account_Code
的值不是数字时,将其策略性地更改为
NULL
。我最初使用了
CROSS APPLY
,但正如
Mikael Eriksson所指出的那样,这导致了相同的错误,因为查询解析器遇到了完全相同的问题来优化我的尝试(谓词下推打败了它)。通过转换为
OUTER APPLY
,它改变了操作的实际意义,使得在外部查询中
X.Account_Code
可以包含
NULL
值,因此需要正确的评估顺序。
您可能会有兴趣阅读
Erland Sommarskog的Microsoft Connect请求,涉及此评估顺序问题。他实际上称之为一个错误。
这里还有其他问题,但我现在无法解决。
补充一句,我今天有个灵感。替代我建议的“传统方式”的方法是带有外部引用的
SELECT
表达式,这也适用于 SQL Server 2000。(我注意到,自从学会了
CROSS/OUTER APPLY
,我在旧版SQL Server中的查询能力也得到了提高,因为我对
SELECT
、
ON
和
WHERE
子句的“外部引用”功能变得更加多才多艺!)
SELECT
Account_Code =
Convert(
bigint,
(SELECT A.AccountCode WHERE A.Account_Code NOT LIKE '%[^0-9]%')
),
A.Descr
FROM dbo.Account A
WHERE
Convert(
bigint,
(SELECT A.AccountCode WHERE A.Account_Code NOT LIKE '%[^0-9]%')
) BETWEEN 503100 AND 503205
它比CASE
语句要短得多。