Предотвращение ошибок преобразования данных TSQL

StackOverflow https://stackoverflow.com/questions/165466

  •  03-07-2019
  •  | 
  •  

Вопрос

Я думаю, это лучше всего задать в виде простого примера. Следующий фрагмент SQL вызывает " Ошибка DB-библиотеки: 20049 Уровень серьезности: 4 Сообщение: преобразование данных привело к сообщению переполнения , но почему?

declare @a numeric(18,6), @b numeric(18,6), @c numeric(18,6)
select @a = 1.000000, @b = 1.000000, @c = 1.000000
select @a/(@b/@c)
go 

Чем это отличается от

select 1.000000/(1.000000/1.000000)
go

который работает нормально?

Это было полезно?

Решение

Я столкнулся с той же проблемой в последний раз, когда пытался использовать Sybase (много лет назад). Исходя из мышления SQL Server, я не осознавал, что Sybase попытается вывести десятичные дроби - что математически и должно делать . :)

Из руководства по Sybase :

  

Ошибки арифметического переполнения возникают, когда   новый тип имеет слишком мало десятичных   места для размещения результатов.

И еще дальше:

  

Во время неявных преобразований в числовые   или десятичные типы, потеря масштаба   генерирует ошибку масштаба. Использовать   опция arithabort numeric_truncation   определить насколько серьезна такая ошибка   Считается. Настройка по умолчанию,   arithabort numeric_truncation on,   прерывает утверждение, которое вызывает   ошибка, но продолжает обрабатывать другие   заявления в сделке или   партия. Если вы установите Arithabort   numeric_truncation off, Adaptive   Сервер обрезает результаты запроса и   продолжает обработку.

Итак, предполагая, что потеря точности приемлема в вашем сценарии , вы, вероятно, захотите следующее в начале транзакции:

SET ARITHABORT NUMERIC_TRUNCATION OFF

А затем в конце вашей транзакции:

SET ARITHABORT NUMERIC_TRUNCATION ON

Это то, что решило это для меня много лет назад ...

Другие советы

Это всего лишь предположение, но может ли СУБД посмотреть не на динамическое значение ваших переменных, а только на потенциальные значения? Таким образом, шестизначное число, разделенное на шестнадцатеричное число, может привести к двенадцатимичному числу; в буквальном смысле СУБД знает, что переполнения нет. Тем не менее, все еще не уверен, почему СУБД все равно - разве она не должна возвращать результат двух шестнадцатеричных делений с точностью до 18-десятичного числа?

Поскольку вы объявили переменные в первом примере, ожидается, что результат будет того же объявления (то есть числового (18,6)), но это не так.

Я должен сказать, что первый из них работал в SQL2005 (возвратил 1.000000 [тот же объявленный тип]), а второй возвратился (1.00000000000000000000000 [совершенно другое объявление]).

Не имеет прямого отношения, но, возможно, может сэкономить кому-то время с ошибками арифметического переполнения с помощью Sybase ASE (12.5.0.3).

Я установил несколько значений по умолчанию во временной таблице, которую я собирался обновить позже, и наткнулся на ошибку арифметического переполнения.

declare @a numeric(6,3)

select 0.000 as thenumber into #test --indirect declare

select @a = ( select thenumber + 100 from #test )

update #test set thenumber = @a

select * from #test

Показывает ошибку:

Arithmetic overflow during implicit conversion of NUMERIC value '100.000' to a NUMERIC field .

Что в моей голове должно работать, но не так, как столбец 'thenumber' не был объявлен (или косвенно объявлен как десятичный (4,3)). Таким образом, вы должны были бы косвенно объявить столбец временной таблицы с масштабом и точностью до требуемого формата, как в моем случае было 000.000.

select 000.000 as thenumber into #test --this solved it

Надеюсь, это сэкономит кому-то время :)

scroll top