Ошибка арифметического переполнения при преобразовании varchar в числовой тип данных - PullRequest
1 голос
/ 30 января 2012

Во-первых, позвольте мне заявить, что я прочитал различные подобные посты и не смог выявить сходства между проблемой, с которой столкнулись другие авторы этого сообщения об ошибке, и ситуацией, с которой я столкнулся.Возможно, я не ищу правильно, но вот сценарий.Я пытаюсь найти значения в таблице, которые меньше 70 при преобразовании в числовое значение.Иногда значение может быть сохранено с запятой (т.е. 3080 и т. Д.), Поэтому у меня есть оператор замены, чтобы удалить запятую.Столбец obsValue в запросах ниже - varchar(2000), и я предполагаю, что это как-то связано с этим.Мой первоначальный запрос работал:

Select name, obsValue
From database.dbo.table
Where name in ('LDL') 
and isnumeric(obsvalue) = 1 
and cast(replace(obsvalue,',','') as decimal(18)) < 70

Это возвращает ожидаемые значения, но это не единственное name Я пытаюсь найти.Другие примеры включают ('LDL(CALC)').Использование оператора UNION позволит мне объединять запросы, но, к сожалению, я не контролирую код приложения, и это не вариант.Единственный доступный вариант - использование предложения IN, поэтому в конечном итоге запрос будет выглядеть так, когда я ищу множество значений name:

Select name, obsValue
From database.dbo.table
Where name in ('LDL', 'LDL(CALC)') 
and isnumeric(obsvalue) = 1 
and cast(replace(obsvalue,',','') as decimal(18)) < 70

И, к сожалению, делаю это такпуть, где я получаю сообщение об ошибке.Я прошу прощения, если это уже было ответом в другом месте.Пожалуйста, ссылку, и я дам кредит, когда кредит должен.

Ответы [ 3 ]

1 голос
/ 30 января 2012

Проблема в том, что SQL Server оптимизирует запрос по-разному, когда в предложении IN есть несколько элементов.Вы можете использовать оператор CASE, чтобы предотвратить оптимизацию

SELECT name, obsvalue
FROM database.dbo.table 
WHERE (CASE WHEN ( isnumeric(obsvalue) = 1 
             AND name in ('LDL', 'LDL(CALC)')) 
       THEN cast(replace(obsvalue,',','') as decimal(18))
       ELSE null END) < 70
1 голос
/ 31 января 2012

Вы можете заменить IsNumeric (obsvalue) на (выберите obsvalue, где isnumeric (obsvalue) = 1).

Select name, obsValue
From database.dbo.table
Where name in ('LDL', 'LDL(CALC)') 
and isnumeric(obsvalue) = 1 
and cast(replace((select obsvalue where isnumeric(obsvalue) = 1),',','') as decimal(18)) < 70
1 голос
/ 30 января 2012

В obsvalue могут быть значения, которые слишком велики для вашей функции приведения (как десятичная), но вас это не волнует, потому что они не соответствуют критериям in ().

Попробуйте применить cast () в подзапросе, ограничив ваш запрос до значений obsval, которые вам действительно нужно преобразовать.

Кроме того, поскольку запятые существуют только в том случае, если значение больше 999, а вы тестируете значения меньше 70, замена не требуется. На самом деле вы можете исключить любую строку, содержащую запятую, потому что знаете, что она слишком высокая.

...