5

I am trying to take an average of a column in my database. The column is AMOUNT and it is stored as NVARCHAR(300),null.

When I try to convert it to a numeric value I get the following error:

Msg 8114, Level 16, State 5, Line 1
Error converting datatype NVARCHAR to NUMBER

Here is what I have right now.

SELECT AVG(CAST(Reimbursement AS DECIMAL(18,2)) AS Amount
FROM Database
WHERE ISNUMERIC(Reimbursement) = 1 
  AND Reimbursement IS NOT NULL
2
  • Seems like you have some non-numeric values in that column... Commented Aug 18, 2016 at 15:29
  • Which version of SQLServer are you using ? Commented Aug 18, 2016 at 15:32

3 Answers 3

15

You would think that your code would work. However, SQL Server does not guarantee that the WHERE clause filters the database before the conversion for the SELECT takes place. In my opinion this is a bug. In Microsoft's opinion, this is an optimization feature.

Hence, your WHERE is not guaranteed to work. Even using a CTE doesn't fix the problem.

The best solution is TRY_CONVERT() available in SQL Server 2012+:

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

In earlier versions, you can use CASE. The CASE does guarantee the sequential ordering of the clauses, so:

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

Because AVG() ignores NULL values, the WHERE is not necessary, but you can include it if you like.

Finally, you could simplify your code by using a computed column:

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

Then you could write the code as:

select avg(Reimbursement_Value)
from database
where Reimbursement_Value is not null;
Sign up to request clarification or add additional context in comments.

Comments

3

Quote from MSDN...

ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($). For a complete list of currency symbols, see money and smallmoney

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

so try to add to avoid non numeric numbers messing with your ouput..

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

If you are on SQLServer 2012,you could try using TRY_Convert which outputs null for conversion failures..

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

Comments

0

I am guessing that since it is Nvarchar you are going to find some values in there with a '$','.', or a (,). I would run a query likt this:

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

See what you get and my guess you will get some rows returned and then update those rows and try it again.

Currently your query would pull all numbers that are not all numeric which is a reason why it is failing too. Instead try running this:

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

2 Comments

Hi @Wes Palmer I ran the first line and i recieve and output like this. $11,162 $11,162 $11,162 $11,162 $11,162 $10,194 could it be due to the fact that there is a dollar sign leading all my values when I try to conver it to an INT?
Yes the Dollar signs and the comma to separate the thousands from the hundreds would also cause it to fail because it is stored as plain text. So you might have to update these values to just a number then use your script.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.