【问题标题】: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
为什么它没有被截断?
这种转换背后的机制是什么,能用某种公式计算得到的数字吗?


我不是在寻找解决方案。我只是想了解具体的数字。

【问题讨论】:

    标签: php mysql integer iec10967


    【解决方案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_TABLESSTRICT_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 的功能。

      【讨论】:

        猜你喜欢
        • 2014-05-05
        • 2014-12-12
        • 2011-04-17
        • 1970-01-01
        • 1970-01-01
        • 2021-07-19
        • 2014-10-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多