Длинное целое число преобразуется при вставке в более короткий столбец, не обрезается. Зачем? Какая формула?

У меня есть столбец типа integer длиной 10:

`some_number` int(10) unsigned NOT NULL

В этот столбец я вставляю слишком длинный номер:

$some_number = 715988985123857;
$query = "INSERT INTO this_table SET some_number = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('i', $some_number);
$stmt->execute();

Когда я смотрю на то, что в таблице, число теперь:

2147483647

Как и почему 715988985123857превратиться в 2147483647?
Почему оно не обрезалось?
Каков механизм этого преобразования, и можно ли рассчитать полученное число по некоторой формуле?


Я не ищу решение. Я просто хочу понять конкретное число.

3 ответа

Решение

http://dev.mysql.com/doc/refman/5.0/en/integer-types.html

Целочисленное переполнение установит максимально допустимое число в БД как

2147483647

Так вам нужно bigint тип данных для хранения большего целого числа

Как и почему 715988985123857 превратился в 2147483647?
Почему оно не обрезалось?
Каков механизм этого преобразования, и можно ли рассчитать полученное число по некоторой формуле?

Поведение зависит от настройки режима SQL строгого SQL:

Строгий режим контролирует, как MySQL обрабатывает недопустимые или отсутствующие значения в операторах изменения данных, таких как INSERT или UPDATE.

В руководстве MySQL есть глава, объясняющая, как MySQL обрабатывает значения вне диапазона: Обработка вне диапазона и Переполнение:

[...] Если никакие ограничительные режимы не включены, MySQL обрезает значение до соответствующей конечной точки диапазона и сохраняет полученное значение.

В случае целочисленного типа максимальное значение:

  • 2147483647 для подписанного типа
  • 4294967295 для беззнакового типа

Поскольку ваш запрос не выдал ошибку, а вместо этого столбец был обновлен с максимально допустимым значением, вы можете предположить, что строгий режим SQL не включен на вашем сервере. Вы можете проверить это, запустив:

SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;

Ни один из них не будет содержать STRICT_TRANS_TABLES ни STRICT_ALL_TABLES значения (подробнее о значениях в MySQL man: sql_mode).
Возьмите этот пример, чтобы проверить различные варианты поведения между режимами:

mysql> create table test_sql_mode(id int);
mysql> set sql_mode = 'STRICT_TRANS_TABLES';
mysql> SELECT @@SESSION.sql_mode;
+---------------------+
| @@SESSION.sql_mode  |
+---------------------+
| STRICT_TRANS_TABLES |
+---------------------+
1 row in set (0.00 sec)

mysql> insert into test_sql_mode(id) value(123456789123456789);
ERROR 1264 (22003): Out of range value for column 'id' at row 1

mysql> select * from test_sql_mode;
Empty set (0.00 sec)

mysql> set sql_mode = '';
mysql> SELECT @@SESSION.sql_mode;
+--------------------+
| @@SESSION.sql_mode |
+--------------------+
|                    |
+--------------------+
1 row in set (0.00 sec)

mysql> insert into test_sql_mode(id) value(123456789123456789);
Query OK, 1 row affected, 1 warning (0.05 sec)

mysql> show warnings;
+-------+------+---------------------------------------------+
| Level | Code | Message                                     |
+-------+------+---------------------------------------------+
| Error | 1264 | Out of range value for column 'id' at row 1 |
+-------+------+---------------------------------------------+

mysql> select * from test_sql_mode;
+------------+
| id         |
+------------+
| 2147483647 |
+------------+
1 row in set (0.00 sec)

Короче говоря, в строгом режиме значение вне допустимого диапазона приводит к ошибке, без - значение корректируется до допустимого предела и выдается предупреждение.


Что касается этого вопроса:

можно ли рассчитать полученное число по какой-то формуле?

Я не знаю ни одной простой и чистой формулы MySQL. Вы должны проверить тип данных и длину:

select data_type, numeric_precision, numeric_scale
from information_schema.columns
where table_schema = "test_database"
and table_name = "test_sql_mode"
and column_name = "id"

... и на основании этого определить допустимый предел.

Non-SQL? Проверка данных (на стороне сервера и на стороне клиента) является решением.

Well as far as i know, it doesn't have anything to do with PHP, bcx.

  • Если PHP встречает число за пределами целочисленного типа, оно будет интерпретироваться как число с плавающей точкой.
  • Кроме того, операция, результатом которой является число, выходящее за пределы целочисленного типа, вместо этого вернет число с плавающей запятой.

So it will be the functionality of SQL which changes the value.

Другие вопросы по тегам