Ошибка арифметического переполнения, если Varchar превышает 999, ПОЧЕМУ?

#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 значения здесь:

  1. '1000' что является varchar(4)
  2. 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. Если он был преобразован в a decimal(4,1) , то почему '999'/100.0 возвращает значение 9.990000? не должно ли это также вызвать арифметическое переполнение?

2. numeric и decimal являются синонимами @Alexw .

3. И нет, 999 достаточно «мал», чтобы поместиться в a decimal(4,1) , так что преобразование прошло успешно.