php - El entero largo se transforma cuando se inserta en una columna más corta, no truncada. ¿Por qué? ¿Cuál es la fórmula?
mysql integer (3)
http://dev.mysql.com/doc/refman/5.0/en/integer-types.html
El desbordamiento entero establecerá el número máximo permitido en la base de datos como
2147483647
Por lo tanto, necesita un bigint
datos bigint
para almacenar un entero más grande
Tengo una columna de tipo integer
con longitud 10:
`some_number` int(10) unsigned NOT NULL
En esta columna, inserto un número que es demasiado largo:
$some_number = 715988985123857;
$query = "INSERT INTO this_table SET some_number = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param(''i'', $some_number);
$stmt->execute();
Cuando miro lo que hay en la tabla, el número ahora es:
2147483647
¿Cómo y por qué el 715988985123857
convirtió en 2147483647
?
¿Por qué no se truncó?
¿Cuál es el mecanismo detrás de esta transformación y se puede calcular el número resultante con alguna fórmula?
No estoy buscando una solución. Solo quiero entender el número específico.
Hasta donde yo sé, no tiene nada que ver con PHP, bcx.
- Si PHP encuentra un número más allá de los límites del tipo entero, se interpretará como un flotante.
- Además, una operación que da como resultado un número más allá de los límites del tipo entero devolverá una flotación en su lugar.
Entonces será la funcionalidad de SQL la que cambie el valor.
¿Cómo y por qué el 715988985123857virtió en 2147483647?
¿Por qué no se truncó?
¿Cuál es el mecanismo detrás de esta transformación y se puede calcular el número resultante con alguna fórmula?
El comportamiento depende de la configuración de MySQL Strict SQL Mode :
El modo estricto controla la forma en que MySQL maneja los valores inválidos o perdidos en las instrucciones de cambio de datos como INSERT o UPDATE.
Hay un capítulo en el manual de MySQL que explica cómo MySQL maneja los valores fuera de rango: fuera de rango y manejo de desbordamiento :
[...] Si no se habilitan modos restrictivos, MySQL recorta el valor al punto final apropiado del rango y almacena el valor resultante en su lugar.
En el caso de Integer Type , el valor máximo es:
- 2147483647 para tipo firmado
- 4294967295 para tipo sin firmar
Como su consulta no arrojó un error, sino que la columna se actualizó con el valor máximo permitido, puede suponer que el modo SQL estricto no está habilitado en su servidor. Puede verificarlo ejecutando:
SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;
Ninguno de ellos contendrá STRICT_TRANS_TABLES
ni STRICT_ALL_TABLES
valores (más sobre los valores en MySQL man: sql_mode
).
Tome este ejemplo para probar los diferentes comportamientos entre modos:
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)
En resumen, con el modo estricto, el valor fuera de rango produce un error, sin - el valor se ajusta al límite permitido y se produce una advertencia.
En cuanto a esta pregunta:
¿El número resultante se puede calcular con alguna fórmula?
No conozco ninguna fórmula simple y pura de MySQL. Debería verificar el tipo de datos y la longitud:
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"
... y en base a eso determinar el límite permitido.
No sql? La validación de datos (del lado del servidor y del lado del cliente) es la solución.