7

我刚刚在数据库中发现了一个查询失败,导致报告失败。查询的基本要点:

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 为数字的所有行转储到临时表中,然后查询该字段在指定范围内的行,我该怎么做才是最佳的?

我的第一个解析纯粹是为了尝试分析返回的数据并查看发生了什么:

Select *
From (
   Select *
   From table
   Where IsNull(myField, '') <> ''
   And IsNumeric(myField) = 1
) t0
Where Convert(int, myField) Between @StartRange And @EndRange

但是我遇到了与第一个查询相同的错误,我不确定我是否理解,因为此时我没有转换任何不应该是数字的数据。子查询应该只返回 myField 包含数字数据的行。

也许我需要我的早茶,但这对任何人都有意义吗?另一双眼睛会有所帮助。

提前致谢

4

4 回答 4

6

IsNumeric 仅告诉您字符串可以转换为SQL Server 中的一种数字类型。它可能能够将其转换为货币或浮点数,但可能无法将其转换为 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)
于 2010-09-21T13:03:07.060 回答
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
  • 第一种技术是“中间物化”:它强制在工作台上进行排序。
  • 2nd依靠CASE ORDER评估保证
  • 既不漂亮也不时髦

SQL 是声明性的:你告诉优化器你想要什么,而不是如何去做。上面的技巧迫使事情以一定的顺序完成。

于 2010-09-21T12:49:30.073 回答
1

不确定这是否对您有帮助,但我确实在某处读到使用 CONVERT 的不正确转换总是会在 SQL 中产生错误。所以我认为最好在 where 子句中使用 CASE 以避免 CONVERT 在所有行上运行

于 2010-09-21T12:50:05.483 回答
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
于 2010-09-21T12:51:06.687 回答