如何根据字段是否可以转换为数字进行过滤?

时间:2011-01-26 19:14:20

标签: sql tsql sql-server-2000

我的报告已经使用了很长时间 - 实际上,公司的发票系统在很大程度上依赖于此报告(免责声明:我没有写过)。过滤基于VarChar(50)类型的字段是否落在用户传入的两个数值之间。

问题在于,现在过滤数据的字段不仅具有简单的非数字值,例如'/ A','TEST'和一系列其他非数字数据,而且还具有数值似乎在藐视我能想到的任何类型的数字转换。

以下(简化)测试查询演示了失败:

Declare  @StartSummary Int,
         @EndSummary Int

Select   @StartSummary = 166285,
         @EndSummary = 166289

Select   SummaryInvoice
From     Invoice
Where    IsNull(SummaryInvoice, '') <> ''
And      IsNumeric(SummaryInvoice) = 1
And      Convert(int, SummaryInvoice) Between @StartSummary And @EndSummary

我还尝试使用bigint,real和float进行转换,所有这些都给了我类似的错误:

  

Msg 8115,Level 16,State 2,Line 7   算术溢出错误转换   表达式到数据类型int。

我尝试过其他较大的数值数据类型,例如BigInt,但错误相同。我还尝试使用子查询来回避转换问题,只提取具有数字数据的字段,然后在包装器查询中转换它们,但随后我得到其他错误,这些错误都是主题上的所有变体,表明存储的值SummaryInvoice字段无法转换为相关数据类型。

如果没有将具有数字SummaryInvoice字段的记录提取到临时表然后查询临时表,是否有任何一步解决方案可以解决此问题?

修改:这是我怀疑导致问题的字段数据:

  

SummaryInvoice

     
     

11111111111111111111111111

IsNumeric声明此字段为数字 - 。但是尝试将其转换为BigInt会导致算术溢出。有任何想法吗?它似乎不是一个孤立的事件,似乎有许多记录填充了导致此问题的数据。

4 个答案:

答案 0 :(得分:3)

似乎你会遇到ISNUMERIC函数的问题,因为如果可以转换为任何数字类型,它会返回1(包括.,,{{1}等等)。如果您的号码长于2 ^ 63-1,则可以使用e0DECIMAL。我不确定您是否可以使用NUMERICPATINDEX上执行正则表达式查看,但如果可以的话,那么您应该尝试一下:

SummaryInvoice

答案 1 :(得分:1)

您无法保证将应用WHERE子句过滤器的顺序。

解除内在和外在的一个丑陋的选择。

SELECT
   *
FROM
    (
    Select   TOP 2000000000
             SummaryInvoice
    From     Invoice
    Where    IsNull(SummaryInvoice, '') <> ''
    And      IsNumeric(SummaryInvoice) = 1
    ORDER BY SummaryInvoice
    ) foo
WHERE
    Convert(int, SummaryInvoice) Between @StartSummary And @EndSummary

另一个使用CASE

Select   SummaryInvoice
From     Invoice
Where    IsNull(SummaryInvoice, '') <> ''
    And     
    CASE WHEN IsNumeric(SummaryInvoice) = 1 THEN Convert(int, SummaryInvoice) ELSE -1 END
          Between @StartSummary And @EndSummary

YMMV

编辑:问题更新后

  1. 使用decimal(38,0)not int
  2. 将ISNUMERIC(SummaryInvoice)更改为ISNUMERIC(SummaryInvoice + '0e0')

答案 2 :(得分:0)

AND与IsNumeric(SummaryInvoice)= 1,不会在SQL Server中短路。

但可能你可以使用

AND(CASE IsNumeric(SummaryInvoice)= 1那么转换(int,SummaryInvoice)ELSE 0 END) 在@StartSummary和@EndSummary之间

答案 3 :(得分:0)

您的第一个问题是修复您的数据库结构,以便糟糕的数据无法进入该字段。你正在为需要缝合的伤口放一个创可贴,并想知道它为什么不愈合。

数据库重构并不好玩,但需要在出现数据完整性问题时完成。我假设你不是真的为11,111,111,111,111,111,111,111,111或'test'开具发票。因此,不要允许输入这些值(如果您不能将结构更改为正确的数据类型,请考虑触发以防止错误数据进入)并删除您确实存在的错误数据。