我如何查询“之间”非数字字段上的数字数据?

发布于 2024-09-24 04:11:11 字数 889 浏览 6 评论 0原文

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

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、1号线 将 nvarchar 值“/A”转换为 int 数据类型时转换失败。

无法将 myField 为数字的所有行转储到临时表中,然后查询该字段在指定范围内的行,什么我可以做到这一点吗?

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

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

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

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

提前致谢

I've got a query that I've just found in the database that is failing causing a report to fall over. The basic gist of the query:

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

Now, myField doesn't contain numeric data in all the rows [it is of nvarchar type]... but this query was obviously designed such that it only cares about rows where the data in this field is numeric.

The problem with this is that T-SQL (near as I understand) doesn't shortcircuit the Where clause thus causing it to ditch out on records where the data is not numeric with the exception:

Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value '/A' to data type int.

Short of dumping all the rows where myField is numeric into a temporary table and then querying that for rows where the field is in the specified range, what can I do that is optimal?

My first parse purely to attempt to analyse the returned data and see what was going on was:

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

But I get the same error I did for the first query which I'm not sure I understand as I'm not converting any data that shouldn't be numeric at this point. The subquery should only have returned rows where myField contains numeric data.

Maybe I need my morning tea, but does this make sense to anyone? Another set of eyes would help.

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

难如初 2024-10-01 04:11:12

使用 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

Use a CASE statement.

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
隐诗 2024-10-01 04:11:11

IsNumeric 仅告诉您该字符串可以转换为 SQL Server 中的数字类型之一。它可能能够将其转换为货币或浮点数,但可能无法将其转换为整数。

将您的更改

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)

IsNumeric only tells you that the string can be converted to one of the numeric types in SQL Server. It may be able to convert it to money, or to a float, but may not be able to convert it to an int.

Change your

IsNumeric(myField) = 1

to be:

not myField like '%[^0-9]%' and LEN(myField) < 9

(that is, you want myField to contain only digits, and fit in an int)

Edit examples:

select ISNUMERIC('.'),ISNUMERIC('£'),ISNUMERIC('1d9')

result:

----------- ----------- -----------
1           1           1

(1 row(s) affected)
2024-10-01 04:11:11

您必须强制 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
  • 解决方案。第一种技术是“中间物化”:它强制在工作表上进行排序。
  • 第二个依赖于 CASE ORDER 评估得到保证 SQL
  • 既不是漂亮的,也不是精巧的

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

You'd have to force SQL to evaluate the expressions in a certain order.
Here is one solution

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

and another

Select *
From table
Where

CASE
   WHEN IsNumeric(myField) = 1 And IsNull(myField, '') <> ''
   THEN Convert(int, myField) ELSE @StartRange-1
END Between @StartRange And @EndRange
  • The first technique is "intermediate materialisation": it forces a sort on a working table.
  • The 2nd relies on CASE ORDER evaluation is guaranteed
  • Neither is pretty or whizzy

SQL is declarative: you tell the optimiser what you want, not how to do it. The tricks above force things to be done in a certain order.

非要怀念 2024-10-01 04:11:11

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

Not sure if this helps you, but I did read somewhere that incorrect conversion using CONVERT will always generate error in SQL. So I think it would be better to use CASE in where clause to avoid having CONVERT to run on all rows

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文