繁体   English   中英

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

[英]SQL Server 2008 R2 data type conversion error

我有一列数据类型为varchar ,其中一些包含数字(十进制)值。 我需要找到所有数值均大于100的行。我正在使用ISNUMERIC来筛选包含数字的行,然后尝试使用CASTCONVERT将数字更改为decimal值。 我读了另一个建议,说使用子查询可以解决问题,但是我也尝试过运气不好

这是我收到的错误消息:

将varchar转换为数值数据类型的算术溢出错误。

码:

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)

这是您的查询:

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
                    )

您假设在select之前过滤了where子句。 这不是真的。 实际上,SQL Server将cast()推送到读取数据的操作。 然后,它随后应用过滤器。

实际上,子查询和公用表表达式也不保证求值顺序。 什么是case (至少在这种情况下不涉及聚合)。 因此,您可以将查询编写为:

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;

我认为没有理由进行子查询。

查询存在一些问题,但是最主要的问题(一个引起错误的问题)非常简单:您的field_name > 100.00条件在进行比较之前没有将VARCHAR字段转换为数字类型。 将其更改为CONVERT(DECIMAL(38, 18), [field_name])将解决您所看到的错误。

运行以下命令一次,看它是否起作用,然后取消注释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
                     );

但是 ,仍然存在一些问题:

  1. 如问题所示,子查询没有任何意义返回返回已转换值的列表。 为了在此处发布的目的,查询可能已被更改,因此以其真实形式更有意义,但是子查询不是必需的,而且还是无济于事。
  2. CASTDECIMAL并未指定“精度和小数位数”。 默认值分别是18和0。 意思是,您正在将字符串转换为DECIMAL(18, 0) 在这里似乎没有任何影响,但是最好指定这些值。 运行SELECT CAST('123.456' AS DECIMAL)将仅返回123
  3. 您实际上不需要用逗号过滤掉值,因为可以将其删除,而剩下的值可以转换。 当然,除非您有一些类似12,34,56,78代码。 但是,如果它们是有效数字,例如1,234.56 ,则可以使用REPLACE([field_name], ',', '')
  4. 将以下两行添加到上述示例顶部的INSERT 中将出错:

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

可以通过执行以下所有操作(将上面的查询替换为下面的查询,但保留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