Предотвращение ошибок преобразования данных TSQL
-
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 попытается вывести десятичные дроби - что математически и должно делать . :) Р>
Ошибки арифметического переполнения возникают, когда новый тип имеет слишком мало десятичных места для размещения результатов.
И еще дальше:
Во время неявных преобразований в числовые или десятичные типы, потеря масштаба генерирует ошибку масштаба. Использовать опция 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
Надеюсь, это сэкономит кому-то время :)