USE AdventureWorks2014SELECT 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 BonusCategoryFROM 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 NULLORDER 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 AdventureWorks2014SELECT 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 BonusCategoryFROM person.Person as PINNER 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.