我有一个查询,我刚刚在数据库中找到失败导致报告失败的查询。查询的基本要点:
Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
And Convert(int, myField) Between @StartRange And @EndRange
现在,myField在所有行中都不包含数字数据[它是nvarchar类型] ...但是这个查询显然是设计成只关心这个字段中的数据是数字的行。
这个问题是T-SQL(我理解的附近)不会使Where子句短路,从而导致它在数据不是数字的记录上抛弃,但有例外:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value '/A' to data type int.
如果没有将myField为numeric的所有行转储到临时表中,然后查询该字段在指定范围内的行,那么我能做的最佳是什么?
我的第一个解析纯粹是为了尝试分析返回的数据,看看发生了什么:
Select *
From (
Select *
From table
Where IsNull(myField, '') <> ''
And IsNumeric(myField) = 1
) t0
Where Convert(int, myField) Between @StartRange And @EndRange
但是我得到的错误与第一个查询相同,我不确定我理解,因为此时我没有转换任何不应该是数字的数据。子查询应该只返回myField包含数字数据的行。
也许我需要早茶,但这对任何人都有意义吗?另一组眼睛会有所帮助。
提前致谢
答案 0 :(得分:6)
IsNumeric仅告诉您该字符串可以转换为 SQL Server中的数字类型之一。它可以将它转换为money或float,但可能无法将其转换为int。
更改您的
IsNumeric(myField) = 1
是:
not myField like '%[^0-9]%' and LEN(myField) < 9
(也就是说,你希望myField只包含数字,并且适合int)
编辑示例:
select ISNUMERIC('.'),ISNUMERIC('£'),ISNUMERIC('1d9')
结果:
----------- ----------- -----------
1 1 1
(1 row(s) affected)
答案 1 :(得分:3)
您必须强制SQL按特定顺序评估表达式。 这是一个解决方案
Select *
From ( TOP 2000000000
Select *
From table
Where IsNumeric(myField) = 1
And IsNull(myField, '') <> ''
ORDER BY Key
) t0
Where Convert(int, myField) Between @StartRange And @EndRange
和另一个
Select *
From table
Where
CASE
WHEN IsNumeric(myField) = 1 And IsNull(myField, '') <> ''
THEN Convert(int, myField) ELSE @StartRange-1
END Between @StartRange And @EndRange
SQL是声明性的:您告诉优化器您想要什么,而不是如何操作。上面的技巧迫使事情以某种顺序完成。
答案 2 :(得分:1)
不确定这是否对您有所帮助,但我确实在某处读过使用CONVERT的错误转换将始终在SQL中生成错误。所以我认为最好在where子句中使用CASE以避免让CONVERT在所有行上运行
答案 3 :(得分:1)
使用CASE
声明。
declare @StartRange int
declare @EndRange int
set @StartRange = 1
set @EndRange = 3
select *
from TestData
WHERE Case WHEN ISNUMERIC(Value) = 0 THEN 0
WHEN Value IS NULL THEN 0
WHEN Value = '' THEN 0
WHEN CONVERT(int, Value) BETWEEN @StartRange AND @EndRange THEN 1
END = 1