Ошибка преобразования при преобразовании значения nvarchar ‘$ 28 926,25’ в тип данных int

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

 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 ' 11%'
     GROUP BY sp.BusinessEntityID) AS result 
WHERE 
    result.BusinessEntityID = p.BusinessEntityID 
    OR result.TotalSales IS NULL
ORDER BY 
    result.BusinessEntityID 
 

Полное сообщение об ошибке

Сообщение 245, уровень 16, состояние 1, строка 2
не удалось преобразовать при преобразовании значения nvarchar ‘$ 28 926,25’ в тип данных int.

Комментарии:

1. FORMAT(sum(soh.SubTotal),'c','en-us') -> CAST(result.TotalSales AS int) Форматирование вывода (при необходимости) должно выполняться в последнюю очередь

2. @LukaszSzozda Сообщение 4104, уровень 16, состояние 1, строка 9 Многосоставный идентификатор «результат. Не удалось привязать итоговые продажи. введите свое решение, и это то, что я получил

3. Не используйте объединения в старом стиле . Хуже всего смешивание синтаксиса старого стиля и нового (наилучшего) синтаксиса объединения в одном запросе.

Ответ №1:

При программировании практически на ЛЮБОЙ платформе необходимо понимать, что преобразование числовых значений типа like 123.45 в строковые или текстовые значения типа like "123.45" является удивительно медленной и дорогостоящей операцией. Они могут выглядеть одинаково, но это разные значения, и во многом благодаря интернационализации / культурным проблемам преобразования между ними не являются тривиальными. Всегда стремитесь минимизировать эти преобразования, и когда они вам понадобятся, оставьте это до последнего возможного момента.

SQL Server здесь не исключение. Он может быть очень требовательным к смешиванию чисел и текста.

Для этого вопроса вложенный внутренний запрос принимает sum(soh.SubTotal) выражение, представляющее собой число, и оборачивает его в FORMAT() вызов функции, который создает текстовое поле. Позже мы попытаемся использовать результат во внешнем запросе, как если бы это снова было число.

Не делайте этого!

Подождите, чтобы отформатировать результат до SELECT предложения внешнего оператора, в последний возможный момент. Это позволяет нам полностью удалить CAST() s из CASE выражения.

Кроме того, НИКОГДА не используйте старый A,B WHERE синтаксис соединения. Он устарел уже более 25 лет.

 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 ' 11%'
       GROUP BY sp.BusinessEntityID
    ) result ON (result.BusinessEntityID = p.BusinessEntityID OR result.TotalSales is null)
ORDER BY result.BusinessEntityID 
 

Еще лучше, даже не преобразовывайте в строку / текст в предложении SELECT!Пусть клиентская программа или средство создания отчетов обработают эту часть. Это еще один способ, которым мы можем следовать указаниям «оставить преобразование до последнего возможного момента» в первом абзаце.