#sql #sql-server #tsql
Вопрос:
Я обнаружил странную проблему в своей базе данных, я смог ее исправить, но я не понимаю, ПОЧЕМУ эта ошибка возникла в первую очередь. Я использую Microsoft SQL Server 2017.
Следующий код возвращает ошибку арифметического переполнения:
SELECT '1000' / 100.0 FROM table_name
SELECT '1000.0' / 100.0 FROM table_name
Возвращает Ошибку:
Ошибка арифметического переполнения при преобразовании varchar в тип данных numeric.
Но что странно, так это то, что следующий код НЕ вызывает ошибки:
SELECT '100' / 100.0 FROM table_name
Возвращает: 1.000000 для каждой строки.
SELECT '999' / 100.0 FROM table_name
Возвращает: 9.990000 для каждой строки.
SELECT '100.0' / 100.0 FROM table_name
Возвращает: 1.000000 для каждой строки.
SELECT '1000' / 100 FROM table_name
Возвращает: 10 для каждой строки.
С тех пор я исправил код так, чтобы он использовал преобразование, прежде чем пытаться выполнять арифметику, но что меня беспокоит, так это то, ПОЧЕМУ код работал без преобразования чисел меньше 1000???? Это действительно не дает мне покоя!
Комментарии:
1. Это происходит из-за тайных правил о масштабе и точности, присвоенных числовым константам. Настоящая мораль заключается в том, чтобы не выполнять арифметику со строками.
Ответ №1:
У вас есть 2 значения здесь:
'1000'
что являетсяvarchar(4)
100.0
что являетсяdecimal(4,1)
В результате при выполнении выражения '1000' / 100.0
varchar
a неявно приводится к a decimal
, так как decimal
имеет более высокий приоритет типа данных. Однако, поскольку самое большое значение decimal(4,1)
, которое может быть сохранено 999.9
, затем значение 1000
переполняется, и вы получаете сообщение об ошибке.
Комментарии:
1. В этом есть смысл. Но это поднимает еще несколько вопросов. 1. Если он преобразует строку в a
decimal(4,1)
, то почему в сообщении об ошибке указывается преобразование вnumeric
? 2. Если он был преобразован в adecimal(4,1)
, то почему'999'/100.0
возвращает значение 9.990000? не должно ли это также вызвать арифметическое переполнение?2.
numeric
иdecimal
являются синонимами @Alexw .3. И нет,
999
достаточно «мал», чтобы поместиться в adecimal(4,1)
, так что преобразование прошло успешно.