简体   繁体   English

SQL Server 2008 R2数据类型转换错误

[英]SQL Server 2008 R2 data type conversion error

I have a column of data type varchar , some of which contain numerical (decimal) values. 我有一列数据类型为varchar ,其中一些包含数字(十进制)值。 I need to find all rows with numerical values > 100. I'm using ISNUMERIC to filter rows that contain numbers, after which I'm trying to use CAST or CONVERT to change the numbers to a decimal value. 我需要找到所有数值均大于100的行。我正在使用ISNUMERIC来筛选包含数字的行,然后尝试使用CASTCONVERT将数字更改为decimal值。 I read another suggestion that said using a sub-query would fix the problem but I've tried that as well with no luck 我读了另一个建议,说使用子查询可以解决问题,但是我也尝试过运气不好

This is the error message I'm receiving: 这是我收到的错误消息:

Arithmetic overflow error converting varchar to data type numeric. 将varchar转换为数值数据类型的算术溢出错误。

Code: 码:

select field_name
from table_name
where ISNUMERIC(field_name) = 1  and
      field_name in (select cast(field_name as decimal)
                     from table_name
                     where ISNUMERIC(field_name) = 1
                       and field_name not like '%,%'
                       and field_name not like '%-%'
                       and field_name != '.'
                       and field_name > 100.00)

This is your query: 这是您的查询:

select field_name
from table_name
where ISNUMERIC(field_name) = 1  and
      field_name in (select cast(field_name as decimal)
                     from table_name
                     where ISNUMERIC(field_name) = 1 and
                          field_name not like '%,%' and
                          field_name not like '%-%' and
                          field_name <> '.' and
                          field_name > 100
                    )

You are making the assumption that the where clause is filtered before the select . 您假设在select之前过滤了where子句。 This is not true. 这不是真的。 In fact, SQL Server pushes the cast() to the operation that reads the data. 实际上,SQL Server将cast()推送到读取数据的操作。 It then applies the filter afterwards. 然后,它随后应用过滤器。

In fact, subqueries and common table expressions also do not guarantee the order of evaluation. 实际上,子查询和公用表表达式也不保证求值顺序。 What does is case (at least in this case that involves no aggregation). 什么是case (至少在这种情况下不涉及聚合)。 So, you can write your query as: 因此,您可以将查询编写为:

select field_name
from table_name
where (case when ISNUMERIC(field_name) = 1 and
                 field_name not like '%,%' and
                 field_name not like '%-%' and
                 field_name <> '.'
            then cast(field_name as decimal)
       end) > 100;

I see no reason for a subquery. 我认为没有理由进行子查询。

There are a few problems with the query, but the main problem, the one that is causing the error, is fairly simple: your field_name > 100.00 condition is not converting the VARCHAR field to a numeric type prior to doing the comparison. 查询存在一些问题,但是最主要的问题(一个引起错误的问题)非常简单:您的field_name > 100.00条件在进行比较之前没有将VARCHAR字段转换为数字类型。 Changing it to CONVERT(DECIMAL(38, 18), [field_name]) would fix the error that you are seeing. 将其更改为CONVERT(DECIMAL(38, 18), [field_name])将解决您所看到的错误。

Run the following once to see that it does work, then uncomment the AND [field_name] > 100.00 line and run again and you will get the error you have been seeing about "Arithmetic overflow error converting varchar to data type numeric": 运行以下命令一次,看它是否起作用,然后取消注释AND [field_name] > 100.00行并再次运行,您将看到关于“将varchar转换为数值类型的算术溢出错误”的错误信息:

DECLARE @table_name TABLE (field_name VARCHAR(50) NOT NULL);
INSERT INTO @table_name (field_name) VALUES ('1234.5678');
INSERT INTO @table_name (field_name) VALUES ('12.78');
INSERT INTO @table_name (field_name) VALUES ('s');
INSERT INTO @table_name (field_name) VALUES ('2015-01-30');
INSERT INTO @table_name (field_name) VALUES ('51234.5678');
INSERT INTO @table_name (field_name) VALUES ('987651234.56789124');

SELECT field_name
FROM   @table_name
WHERE  ISNUMERIC([field_name]) = 1
AND    [field_name] IN (
                      SELECT CAST([field_name] AS DECIMAL)
                      FROM   @table_name
                      WHERE  ISNUMERIC([field_name]) = 1
                      AND    [field_name] NOT LIKE '%,%'
                      AND    [field_name] NOT LIKE '%-%'
                      AND    [field_name] != '.'
--                      AND    [field_name] > 100.00
                      AND    CONVERT(DECIMAL(38, 18), [field_name]) > 100.00
                     );

BUT , there are still some issues: 但是 ,仍然存在一些问题:

  1. The subquery, as shown in the question, makes no sense to return a list of converted values. 如问题所示,子查询没有任何意义返回返回已转换值的列表。 It is possible that the query has been altered for the purpose of posting here and so makes more sense in its true form, but the subquery isn't needed and isn't helping anyway. 为了在此处发布的目的,查询可能已被更改,因此以其真实形式更有意义,但是子查询不是必需的,而且还是无济于事。
  2. The CAST to DECIMAL is not specifying the Precision and Scale. CASTDECIMAL并未指定“精度和小数位数”。 The default values are 18 and 0, respectively. 默认值分别是18和0。 Meaning, you are casting the strings into a DECIMAL(18, 0) . 意思是,您正在将字符串转换为DECIMAL(18, 0) That does not appear to have any impact here, but it is best to specify the values. 在这里似乎没有任何影响,但是最好指定这些值。 Running SELECT CAST('123.456' AS DECIMAL) will return just 123 . 运行SELECT CAST('123.456' AS DECIMAL)将仅返回123
  3. You don't really need to filter out values with commas as those can be removed, leaving you with a value that can be converted. 您实际上不需要用逗号过滤掉值,因为可以将其删除,而剩下的值可以转换。 Unless, of course, you have some that are codes like 12,34,56,78 . 当然,除非您有一些类似12,34,56,78代码。 But if they are valid numbers, such as 1,234.56 , then you can use REPLACE([field_name], ',', '') 但是,如果它们是有效数字,例如1,234.56 ,则可以使用REPLACE([field_name], ',', '')
  4. Adding the following two lines to the INSERTs at the top of the example above will error: 将以下两行添加到上述示例顶部的INSERT 中将出错:

     INSERT INTO @table_name (field_name) VALUES ('1,234.5678'); INSERT INTO @table_name (field_name) VALUES ('.'); 

All of this can be handled by doing the following (replace the query above with the one below, but keep the DECLARE and INSERT s): 可以通过执行以下所有操作(将上面的查询替换为下面的查询,但保留DECLAREINSERT ):

SELECT field_name, CAST([field_name] AS DECIMAL(38, 18)) AS [DecimalValue]
FROM   @table_name
WHERE  ISNUMERIC(field_name) = 1
AND    field_name NOT LIKE '%,%'
AND    field_name NOT LIKE '%-%'
AND    field_name <> '.'
AND    CONVERT(DECIMAL(38, 18), REPLACE([field_name], ',', '')) > 100.00;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM