MySQL 数值类型溢出处理

来,考考大家一个问题,在 MySQL 中当某一列设置为?int(0)?时会发生什么 ?

为了演示这个问题,我们先要创建一个表

 DROP TABLE IF EXISTS `na`;
CREATE TABLE `na` (
  n1 INT(0)  NOT NULL DEFAULT ‘0‘,
  n2 INT(11) NOT NULL DEFAULT ‘0‘
);

然后我们使用下面的语句往?na?表中插入一些数据

 mysql> INSERT INTO `na` VALUES(520,520),(5201314,5201314);
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

最后我们读取出来看看

 mysql> SELECT * FROM na;
+---------+---------+
| n1      | n2      |
+---------+---------+
|     520 |     520 |
| 5201314 | 5201314 |
+---------+---------+
2 rows in set (0.00 sec)

对的,好像什么都不会发生,没什么问题才是对的,我就怕有什么问题…哈哈

我们这一章节来讲讲整型溢出问题。

MySQL 数值类型溢出处理

当 MySQL 在某个数值列上存储超出列数据类型允许范围的值时,结果取决于当时生效的 SQL 模式

  • 如果启用了严格的 SQL 模式,则 MySQL 会根据 SQL 标准拒绝带有错误的超出范围的值,并且插入失败
  • 如果没有启用任何限制模式,那么 MySQL 会将值裁剪到列数据类型范围的上下限值并存储
    1. 当超出范围的值分配给整数列时,MySQL 会存储表示列数据类型范围的相应端点的值
    2. 当为浮点或定点列分配的值超出指定(或默认)精度和比例所隐含的范围时,MySQL 会存储表示该范围的相应端点的值

这个,应该很好理解吧?

我们举一个例子,假设?t1?表的结构如下

 CREATE TABLE t1 (
    i1 TINYINT,
    i2 TINYINT UNSIGNED
);

如果启用了严格的 SQL 模式,超出范围会发生一个错误

 mysql> SET sql_mode = ‘TRADITIONAL‘;  -- 首先设置严格模式
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
ERROR 1264 (22003): Out of range value for column ‘i1‘ at row 1
mysql> SELECT * FROM t1;
Empty set (0.00 sec)

当严格模式被禁用,值可以插入,但会被裁剪,并且引发一个警告

 mysql> SET sql_mode = ‘‘;  -- 禁用所有模式
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------+
| Level   | Code | Message                                     |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column ‘i1‘ at row 1 |
| Warning | 1264 | Out of range value for column ‘i2‘ at row 1 |
+---------+------+---------------------------------------------+
mysql> SELECT * FROM t1;
+------+------+
| i1   | i2   |
+------+------+
|  127 |  255 |
+------+------+

如果未启用严格 SQL 模式,对于?ALTER TABLELOAD DATA INFILEUPDATE?和多行?INSERT等语句会由于裁剪而发生的列分配转换并且引发一个警告。

而如果启用了严格模式,这些语句会直接失败,并且未插入或更改部分或全部值,具体取决于表是否为事务表和其他因素。

数值表达式求值过程中的溢出会导致错误,例如,因为最大的有符号 BIGINT 值是 9223372036854775807,因此以下表达式会产生错误

 mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in ‘(9223372036854775807 + 1)‘

为了在这种情况下使操作成功,需要将值转换为?unsigned

 mysql> SELECT CAST(9223372036854775807 AS UNSIGNED) + 1;
+-------------------------------------------+
| CAST(9223372036854775807 AS UNSIGNED) + 1 |
+-------------------------------------------+
|                       9223372036854775808 |
+-------------------------------------------+

从另一方面说,是否发生溢出取决于操作数的范围,因此处理前一个表达式的另一种方法是使用精确值算术,因为?DECIMAL?值的范围大于整数

 mysql> SELECT 9223372036854775807.0 + 1;
+---------------------------+
| 9223372036854775807.0 + 1 |
+---------------------------+
|     9223372036854775808.0 |
+---------------------------+

整数数值之间的减去,如果其中一个类型为?UNSIGNED?,默认情况下会生成无符号结果。如果为负,则会引发错误

 mysql> SET sql_mode = ‘‘;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in ‘(cast(0 as unsigned) - 1)‘

这种情况下,如果启用了?NO_UNSIGNED_SUBTRACTION?SQL 模式,则结果为负

 mysql> SET sql_mode = ‘NO_UNSIGNED_SUBTRACTION‘;
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
|                      -1 |
+-------------------------+

如果此类操作的结果用于更新?UNSIGNED?整数列,则结果将裁剪为列类型的最大值,如果启用了?NO_UNSIGNED_SUBTRACTION?则裁剪为?0。但如果启用了严格的 SQL 模式,则会发生错误并且列保持不变。

后记

一切都是套路,套路….基本都和 SQL 模式有关…

原文地址:https://blog.51cto.com/14230003/2432707

时间: 2024-07-31 01:28:04

MySQL 数值类型溢出处理的相关文章

Mysql 数值类型

Mysql数值类型 整数型 小数型(浮点数) 日期时间型

关于Mac系统中SequelPro工具对于Mysql数值类型nt(M)存值的bug

说问题之前,聊表一下mysql数值类型int.众所周知,mysql数值类型int占四个字节,有符号.无符号整形存储的范围不同,有符号范围-2147483648 - 2127483647,无符号范围是0 - 4294967295(2^32是偶数,这里为什么是奇数,如果不清楚请自行补计算机位运算).Mysql类型关键字后面的括号内指定整数值的显示宽度(例如,INT(4)).该可选显示宽度规定用于显示宽度小于指定的列宽度的值时从左侧填满宽度.显示宽度并不限制可以在列内保存的值的范围,也不限制超过列的指

mysql numberic types ---- mysql 数值类型-简介

编程语言中大多都有数据类型一说.虽然mysql 的sql 语句与标准sql 有别.但是宏观上看还是差不多的:下面我们说一下mysql数据库中的数值类型 一.在mysql在有那些类型可以表示数值: 1.bit[(M)] 如果没有指定M的话.这种情况下M默认是1.也就是说也就是说它只能保存一个位.一个要么是零,要么是一:M可以在[1,64]当中取 mysql> create table t(x bit); Query OK, 0 rows affected (0.00 sec) mysql> in

MySQL数值类型

MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型 MySQL支持所有标准SQL数值数据类型. 这些类型包括严格数值数据类型(INTEGER.SMALLINT.DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT.REAL和DOUBLE PRECISION). 关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词. BIT数据类型保存位字段值,并且支持MyIS

20141230 mysql数值类型和列属性一

枚举字符串 枚举字符串指的是在定义之初就确定要存放的字符串有哪些,然后在数据进行存储的时候就只能存储已经定义过的字符串,只能使用任意的一个字符串.(单选框) 语法:enum 字段名 enum(字符串1,字符串2,-); 枚举采用最多2个字节保存数据,最多能存65535个数据 枚举的意义 1. 规范数据:没有进行维护的数据不能插入 2. 节省空间:实际存储的数据是数字 虽然SQL是一种强类型语言,但是SQL能够自动转换数据类型(与php一样) select有一个特点:后面可以跟任意表达式 证明枚举

MySQL的数值类型,时间

数值类型 整数型 tinyint  smallint  mediumint  int|integer  bigint 注意: 1, 如何选择数据类型,我们的原则是:够用就行!尽量的选择占用内存小的整型,而且效率也更快! 2,可以使用unsigned来控制是否有符号位,如果不写,缺省值是有符号的 MySQL不会进行自动类型转换,如果超出了指定类型的范围,就直接报错! 3,可以指定数据显示的最小宽度,以达到统一显示的目的,通常的做法就是使用zerofill来进行填充 如果插入的数据,超出了指定的显示

mysql 数值与字符类型 长度梳理

上述表格中的数值类型都是定长的,也就是说,无论你存的数值是多少,多大或者多小,占用的存储字节大小都是固定的.例如,之前设置的int(1),虽然M值是1个字符,但是它所占用的空间大小永远都是4个字节的大小,换句话说就是,你可以存入有符号整型从-2 147 483 648到2 147 483 647包括这两个数的中间任何一个数.int(1)和int(11)占用的是4个字节,可以存入上述这些数,tinyint(1)和tinyint(4)占用的是1个字节,可以存入从-128到127的数. 那么,这个我们

MYSQL支持的数据类型-数值类型

一.数值类型分类 MYSQL支持所有标准SQL中的数值类型,其中包括严格数值类型(INTEGER.SMALLINT.DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT.REAL和DOUBLE PRECISON),并在此基础上扩展增加了TINYINT.MEDIUMINT.BIGINT这三种整型,并增加了BIT类型,用来存放位数据 其中整数类型包括:TINYINT.SMALLINT.MEDIUMINT.INT(INTEGER).BIGINT 浮点数类型包括:FLOAT.DOUBLE

MySQL基础 三 数值类型,索引

My 1am,1pm 数值类型 Int(4) Float(5,2) Varchar(4) 枚举类型 Enum('female','male') Set('book','football','A'-.最多64个) 约束条件 Null                         Default                        Extra 默认为允许                   默认null Not null                     default 值 Key