Skip to content
Advertisement

Conversion failed when converting the nvarchar value ‘$28,926.25’ to data type int

USE AdventureWorks2014

SELECT 
    result.BusinessEntityID, 
    p.FirstName, p.LastName, 
    result.TotalSales, '2011' AS SalesYear, 
    CASE 
        WHEN CAST(result.TotalSales AS int) > 1000000 THEN 'MillionPlus'
        WHEN CAST(result.TotalSales AS int) < 100000 THEN 'Warning'
        ELSE 'Met Expectations'
    END AS BonusCategory
FROM 
    person.Person AS P, 
    (SELECT sp.BusinessEntityID, FORMAT(sum(soh.SubTotal), 'c', 'en-us') AS TotalSales 
     FROM sales.SalesPerson as sp 
     RIGHT JOIN sales.SalesOrderHeader as SOH ON sp.BusinessEntityID = soh.SalesPersonID
     WHERE soh.orderdate LIKE '%2011%'
     GROUP BY sp.BusinessEntityID) AS result 
WHERE 
    result.BusinessEntityID = p.BusinessEntityID 
    OR result.TotalSales IS NULL
ORDER BY 
    result.BusinessEntityID 

Full error message

Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the nvarchar value ‘$28,926.25’ to data type int.

Advertisement

Answer

Something to understand when programming on almost ANY platform is converting between number values like 123.45 and string or text values like "123.45" is a surprisingly slow and expensive operation. They may look the same, but those are different values, and largely thanks to internationalization/cultural concerns the conversions between them are not trivial. Always seek to minimize these conversions, and when you do need them leave it until the last possible moment.

SQL Server is no exception here. It can be very picky about mixing between numbers and text.

For this question, the nested inner query takes the sum(soh.SubTotal) expression, which is a number, and wraps it in a FORMAT() function call, which creates a text field. We later try to use the result in the outer query as if it were a number again.

Don’t do that!

Wait to format the result until the SELECT clause of the outer statement, at the last possible moment. This allows us to remove the CAST()s from inside the CASE expression completely.

Also, NEVER use the old A,B WHERE join syntax. It’s been out of date for more than 25 years now.

USE AdventureWorks2014
SELECT result.BusinessEntityID, p.FirstName, p.LastName, 
    FORMAT(result.TotalSales,'c','en-us') As TotalSales, '2011' as SalesYear, 
    CASE 
        WHEN result.TotalSales > 1000000 THEN 'MillionPlus'
        WHEN result.TotalSales < 100000 THEN 'Warning'
        ELSE 'Met Expectations'
    END as BonusCategory
FROM person.Person as P
INNER JOIN (
       SELECT sp.BusinessEntityID, FORMAT(sum(soh.SubTotal),'c','en-us') as TotalSales 
       FROM sales.SalesPerson as sp 
       RIGHT JOIN sales.SalesOrderHeader as SOH 
            ON sp.BusinessEntityID = soh.SalesPersonID
       WHERE soh.orderdate LIKE '%2011%'
       GROUP BY sp.BusinessEntityID
    ) result ON (result.BusinessEntityID = p.BusinessEntityID OR result.TotalSales is null)
ORDER BY result.BusinessEntityID 

Even better, don’t even convert to a string/text in the SELECT clause! Let the client program or reporting tool handle this part. This is another way we can follow the “leave the conversion to the last possible moment” guidance in the first paragraph.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement