长整数在插入较短的列时进行转换,而不是截断。为啥?公式是啥?
Posted
技术标签:
【中文标题】长整数在插入较短的列时进行转换,而不是截断。为啥?公式是啥?【英文标题】:Long integer is transformed when inserted in shorter column, not truncated. Why? What is the formula?长整数在插入较短的列时进行转换,而不是截断。为什么?公式是什么? 【发布时间】:2014-06-26 08:16:26 【问题描述】:我有一列 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
?
为什么它没有被截断?
这种转换背后的机制是什么,能用某种公式计算得到的数字吗?
我不是在寻找解决方案。我只是想了解具体的数字。
【问题讨论】:
【参考方案1】:http://dev.mysql.com/doc/refman/5.0/en/integer-types.html
整数溢出会将DB中的最大允许数设置为
2147483647
所以你需要bigint
数据类型来存储更大的整数
【讨论】:
准确来说是最大有符号的32位整数。 是的,maximum signed 32-bit integer
【参考方案2】:
715988985123857如何以及为什么变成2147483647? 为什么它没有被截断? 这种转换背后的机制是什么,能用某种公式计算得到的数字吗?
行为取决于 MySQL Strict SQL Mode 设置:
严格模式控制 MySQL 如何处理数据更改语句(如 INSERT 或 UPDATE)中的无效或缺失值。
MySQL 手册中有一个章节解释了 MySQL 如何处理超出范围的值:Out-of-Range and Overflow Handling:
[...] 如果没有启用限制模式,MySQL 会将值剪切到范围的适当端点并存储结果值。
Integer Type的情况下,最大值为:
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"
...并基于此确定允许的限制。
非sql?数据验证(服务器端和客户端)是解决方案。
【讨论】:
【参考方案3】:据我所知,它与php,bcx没有任何关系。
如果 PHP 遇到超出整数类型界限的数字,它将被解释为浮点数。 此外,导致数字超出整数类型范围的操作将改为返回浮点数。因此,改变值的将是 SQL 的功能。
【讨论】:
以上是关于长整数在插入较短的列时进行转换,而不是截断。为啥?公式是啥?的主要内容,如果未能解决你的问题,请参考以下文章
MySQL:如何使用 CASE 或 IF 匹配较短的列的长度?
为啥 int 被提升为 double 而不是 float 以进行隐式转换