2013-08-21 4 views
0

Моя проблема: у меня есть таблица (импортированная из Excel в SQL Server 2008), которая хранит числа в формате NVARCHAR(255).Преобразование формата NVARCHAR в формат MONEY или FLOAT

Попытки преобразовать эти столбцы FLOAT, MONEY, NUMERIC неудачу с CONVERT или с CAST функциями:

ORIGBAL = CAST(ORIGBAL AS FLOAT) 
ORIGBAL = CAST(ORIGBAL AS MONEY) 
ORIGBAL = CAST(ORIGBAL AS MONEY) 
ORIGBAL = CONVERT(decimal(12,2),ORIGBAL) 

сообщения во всех случаях (или аналогичный сбой сообщения об ошибке):

Ошибка преобразования типа данных nvarchar в числовой.

+2

Вы можете показать примеры некоторых данных, которые вы пытаетесь конвертировать? –

ответ

2

Звучит так, потому что у вас есть числовые данные, хранящиеся в столбце строки, у вас плохие данные. Один из способов определить это:

SELECT key_column, ORIGBAL 
    FROM dbo.tablename 
    WHERE ORIGBAL LIKE '%[^-.0-9]%'; 

Фикс, что данные (они могут содержать запятые, но, вероятно, повреждение хуже, чем, например, некоторые значения с полностью нечисловом данными - в противном случае, отданных в MONEY должны работали) , Если вы обнаружите, что много строк содержат запятые, вы можете просто запустить обновление:

UPDATE dbo.tablename SET ORIGBAL = REPLACE(ORIGBAL, ',', ''); 

Затем выполните вышеуказанный запрос еще раз. Если строки не возвращаются, теперь вы можете преобразовать в «нормальные» числовые типы вместо MONEY или FLOAT, которые действительно должны быть зарезервированы для очень специфических сценариев ИМХО.

Без фиксации данных, вы можете сделать вашу жизнь более сложной, используя выражение CASE во всех ваших запросах:

SELECT key_column, CONVERT(DECIMAL(12,2), CASE 
    WHEN ORIGBAL LIKE '%[^-.0-9]%' THEN ORIGBAL END 
FROM dbo.tablename 
... 

Это даст NULL значения вместо плохих, не-числовых значений. Однако он все равно может выйти из строя, например. это выражение будет передано для 0.0.0.44.02, которое, очевидно, не может быть преобразовано в десятичную. В качестве примера:

DECLARE @x TABLE(ORIGBAL NVARCHAR(255)); 

INSERT @x VALUES('bob'),('0.0.0.44.02'),('32500.40'); 

SELECT ORIGBAL, [status] = CASE WHEN ORIGBAL LIKE '%[^.0-9]%' 
    THEN 'needs correcting' ELSE 'all good' END 
FROM @x; 

Результаты:

bob   needs correcting 
0.0.0.44.02 all good 
32500.40  all good 

Для выявления случаев с несколькими десятичными точками, вы можете сделать:

SELECT ORIGBAL, [status] = CASE WHEN ORIGBAL LIKE '%[^.0-9]%' 
    OR LEN(ORIGBAL)-LEN(REPLACE(ORIGBAL,'.','')) > 1 
    THEN 'needs correcting' ELSE 'all good' END 
FROM @x; 

Результаты:

bob   needs correcting 
0.0.0.44.02 needs correcting 
32500.40  all good 

Вы все еще могут иметь значения, которые превышают возможные конвертировать, например. '123456789.56' слишком большой для DECIMAL(12,2).

В SQL Server 2012, вы будете иметь сокращенную для приведенного выше выражения:

SELECT key_column, TRY_CONVERT(DECIMAL(12,2), ORIGBAL) 
FROM dbo.tablename 
... 

... который будет выход NULL значения даже для более сложных значений, как 0.0.0.44.02.

+0

Спасибо. Любые идеи, как я могу исправить эти данные? я вижу, что, например, Сохраняется 32500.40, формат снова - NVARCHAR (255). Я не могу экспортировать эти данные, поэтому вам нужно преобразовать в SQL. –

+0

Можете ли вы продемонстрировать, как '32500.40' не могут быть преобразованы в' DECIMAL' или 'NUMERIC'? Я очень сомневаюсь, что значение конкретно является проблемой (если столбец не содержит других непечатаемых символов, которые мы не видим). –

+0

Условие ORIGBAL NOT LIKE '% [^ -. 09]%' истинно для всей базы данных. Вышеуказанные функции CONVERT, REPLACE не работают, я уже заменил пробелы на '.' заранее, так я пришел в формат 32500.40 из формата 32500 40. Итак, вы предлагаете начать с нуля? Я не вижу никаких других скрытых символов ... –

0

CAST не реагирует хорошо на запятые и знаки доллара. Возможно, вам повезло с CONVERT ...

SELECT CONVERT(money, '$1,123.45') 

Если вы должны иметь это в десятичной системе счисления, конвертировать в деньги, а затем десятичным ...

SELECT CAST(CONVERT(money, '$1,123.45') AS decimal(12,2)) 
+0

'SELECT CAST ('$ 1,123.45' AS money);' работает отлично - никакой разницы между CAST и CONVERT в этом случае. –

+0

@ Аарон, ты прав. Я мог бы поклясться, что это не удалось в моем тесте, но я просто повторил это. Баттерфингеры, я думаю. – dazedandconfused

Смежные вопросы