将数据类型nvarchar转换为numeric - SQL Server时出错

时间:2016-08-18 15:28:41

标签: sql sql-server

我想在我的数据库中取一个列的平均值。该列为AMOUNT,并存储为NVARCHAR(300),null

当我尝试将其转换为数值时,我收到以下错误:

  

Msg 8114,Level 16,State 5,Line 1
  将数据类型NVARCHAR转换为NUMBER

时出错

这就是我现在所拥有的。

SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1 
  AND Reimbursement IS NOT NULL

3 个答案:

答案 0 :(得分:9)

你会认为你的代码会起作用。但是,SQL Server不保证WHERE子句在SELECT转换发生之前过滤数据库。在我看来这是一个错误。在微软看来,这是一个优化功能。

因此,您的WHERE无法保证正常运作。即使使用CTE也无法解决问题。

SQL Server 2012 +中提供了最佳解决方案TRY_CONVERT()

SELECT AVG(TRY_CONVERT(DECIMAL(18,2), Reimbursement)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL;

在早期版本中,您可以使用CASECASE 确实保证子句的顺序排序,因此:

SELECT AVG(CASE WHEN ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL
                THEN CONVERT(DECIMAL(18,2), Reimbursement))
           END)
FROM Database;

由于AVG()会忽略NULL个值,因此WHERE不是必需的,但如果您愿意,可以将其包括在内。

最后,您可以使用计算列简化代码:

alter database add Reimbursement_Value as
    (CASE WHEN ISNUMERIC(Reimbursement) = 1 AND Reimbursement IS NOT NULL
          THEN CONVERT(DECIMAL(18,2), Reimbursement))
     END);

然后你可以把代码写成:

select avg(Reimbursement_Value)
from database
where Reimbursement_Value is not null;

答案 1 :(得分:2)

Quote from MSDN ...

  

对于某些非数字字符,例如加号(+),减号( - )和有效货币符号(如美元符号($)),ISNUMERIC返回1。有关货币符号的完整列表,请参阅money和s​​mallmoney

select isnumeric('+')---1
select isnumeric('$')---1

所以尽量添加以避免非数字数字弄乱您的输出..

WHERE Reimbursement NOT LIKE '%[^0-9]%'

如果你在SQLServer 2012上,你可以尝试使用TRY_Convert,它为转换失败输出null。

SELECT AVG(try_convert( DECIMAL(18,2),Reimbursement))
from
table

答案 2 :(得分:0)

我猜测,因为它是Nvarchar,你会在那里找到一些带有' $','。'或a(,)的值。我会运行一个查询:

SELECT Amount
FROM database
WHERE Amount LIKE '%$%' OR 
      Amount LIKE '%.%' OR 
      Amount LIKE '%,%'

看看你得到了什么,我猜你会得到一些行返回,然后更新这些行并重新尝试。

目前,您的查询会提取所有不是全数字的数字,这也是它失败的原因。而是尝试运行:

SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
--Changed ISNUMERIC() = to 0 for true so it will only pull numeric numbers.
WHERE ISNUMERIC(Reimbursement) = 0 and Reimbursement IS NOT NULL