Предотвращение ошибок преобразования данных TSQL - PullRequest
4 голосов
/ 03 октября 2008

Я думаю, что это лучше спросить в виде простого примера. Следующий фрагмент SQL вызывает сообщение "Ошибка DB-Library: 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

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

Ответы [ 4 ]

4 голосов
/ 05 октября 2008

Я столкнулся с той же проблемой в последний раз, когда пытался использовать 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

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

1 голос
/ 05 октября 2008

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

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

1 голос
/ 03 октября 2008

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

0 голосов
/ 23 сентября 2015

Не имеет прямого отношения, но, возможно, может сэкономить кому-то время с ошибками арифметического переполнения с помощью 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

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

...