将nvarchar值'test'转换为数据类型int时转换失败

Bob*_*ant 14 sql-server sql-server-2008

上下文:SQL Server 2008

我有一个表,mytable其中包含两NVARCHARid,title.

id列中的所有数据实际上都是数字的,除了包含值'test'的一行.

我希望得到10到15之间的所有ID,所以我需要SQL Server将id列值转换为INTEGER.

我首先使用ISNUMERIC(id) = 1消除非数字值,但SQL Server对此查询非常奇怪.

SELECT 
    in.* 
FROM 
    (SELECT 
         id, title 
     FROM 
         mytable 
     WHERE 
         ISNUMERIC(id) = 1) in
WHERE 
    in.id BETWEEN 10 AND 15
Run Code Online (Sandbox Code Playgroud)

此查询导致以下错误:

将nvarchar值'test'转换为数据类型int时转换失败.

内部查询使用'test'id值删除行,因此'in'不应包含它.为什么SQL Server仍在尝试转换它?

我错过了什么吗?我怎么能绕过这个?

PS我试过WHERE CAST(in.id AS INTEGER) BETWEEN 10 AND 15但也没用.

cyb*_*c87 13

使用TRY_CONVERT函数,它非常方便.

SELECT id, 
       title 
FROM   mytable 
where  TRY_CONVERT(int, id) is not NULL 
and    TRY_CONVERT(int, id) BETWEEN 10 and 15
Run Code Online (Sandbox Code Playgroud)

如果转换失败,TRY_CONVERT将返回null.

对于您的错误,我认为查询优化器在这里混淆了一些东西.看看执行计划,也许它首先在10到15之间过滤值.我的解决方案永远有效.

正如另一位评论者所说,BETWEEN函数在ISNUMERIC之前完成.这是一个简单的例子:

select * into #temp2
from (
select 'test' a
union
select cast(1 as varchar) a
union 
select cast(2 as varchar) a
union 
select cast(3 as varchar) a
)z


SELECT a FROM ( 
SELECT a FROM #temp2 WHERE ISNUMERIC(a) = 1
) b
WHERE b.a BETWEEN 10 AND 15
Run Code Online (Sandbox Code Playgroud)

这个简单的查询是另一种选择:

SELECT a 
FROM #temp2 
WHERE ISNUMERIC(a) = 1 
and a BETWEEN 10 AND 15
Run Code Online (Sandbox Code Playgroud)

  • 使用 isnumeric 总是很危险,因为您无法控制执行计划,它可能会在中间条件之后调用。这是一个更好的方法 (3认同)
  • 问题没有从一开始就用SQL Server版本标记. (2认同)

gof*_*fr1 8

我应该再添加一种XML样式:

SELECT * 
FROM mytable
WHERE CAST(id as xml).value('. cast as xs:decimal?','int') BETWEEN 10 AND 15
Run Code Online (Sandbox Code Playgroud)

转换id为XML,转换值xs:decimal然后转换为integer.如果没有数值,它将被转换为NULL.

在这里,您可以阅读有关XML类型转换规则(链接)的信息.