MySQL 支持的数字数据类型,看看你了解多少

MySQL 支持所有标准 SQL 数字数据类型。这些类型包括精确数字数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC),以及近似数字数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。关键字 INT 是 INTEGER 的同义词,关键字 DEC 和 FIXED 是 DECIMAL 的同义词。

MySQL 支持所有标准 SQL 数字数据类型。这些类型包括精确数字数据类型(INTEGER、SMALLINT、DECIMALNUMERIC),以及近似数字数据类型(FLOAT、REAL DOUBLE PRECISION)。关键字 INT 是 INTEGER 的同义词,关键字 DEC FIXED DECIMAL 的同义词。MySQL 将 DOUBLE 视为 DOUBLE PRECISION(非标准扩展)的同义词。除非启用了 REAL_AS_FLOAT SQL 模式,否则 MySQL 也将 REAL 视为 DOUBLE PRECISION 的同义词(非标准扩展)。

BIT 数据类型存储位值,支持 MyISAMMEMORYInnoDB NDB 表。

有关 MySQL 在表达式求值过程中如何处理超出范围的列赋值和溢出的信息,请参见 "超出范围和溢出处理"。

有关数字数据类型的存储要求,请参见 "数据类型存储要求"。

有关数值运算函数的说明,请参见 "数值函数和运算符"。数值操作数计算结果所使用的数据类型取决于操作数的类型和对操作数执行的操作。更多信息,请参见 "算术运算符"。

数值数据类型语法

对于整数数据类型,M 表示最小显示宽度。最大显示宽度为 255,显示宽度与类型可存储的数值范围无关。

对于浮点和定点数据类型,M 是可存储的总位数。

从 MySQL 8.0.17 起,对于整数数据类型,显示宽度属性已被弃用;预计未来版本的 MySQL 将取消对它的支持。如果为数值列指定 ZEROFILL,MySQL 会自动为列添加 UNSIGNED 属性。

从 MySQL 8.0.17 起,数字数据类型的 ZEROFILL 属性已被弃用;你应该期待在未来版本的 MySQL 中删除对它的支持。请考虑使用其他方法来产生该属性的效果。例如,应用程序可以使用 LPAD() 函数将数字归零到所需的宽度,也可以将格式化后的数字存储在 CHAR 列中。

允许使用 UNSIGNED 属性的数字数据类型也允许使用 SIGNED 属性。不过,这些数据类型默认为 SIGNED ,因此 SIGNED 属性不起作用。

从 MySQL 8.0.17 起,对于 FLOAT、DOUBLE 和 DECIMAL(以及任何同义词)类型的列,UNSIGNED 属性已被弃用;您应该期待在未来的 MySQL 版本中取消对它的支持。请考虑对此类列使用简单的 CHECK 约束。

SERIAL 是 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE 的别名。

整数列定义中的 SERIAL DEFAULT VALUE 是 NOT NULL AUTO_INCREMENT UNIQUE 的别名。

警告:

在一个类型为 UNSIGNED 的整数值之间使用减法时,除非启用了 NO_UNSIGNED_SUBTRACTION SQL 模式,否则结果是无符号的。请参见第 14.10 节 "投影函数和操作符"。

  • BIT[(M)] 位值类型。M 表示每个值的位数,从 1 到 64。如果省略 M,默认值为 1。

  • TINYINT[(M)] [UNSIGNED] [ZEROFILL] 一个非常小的整数。有符号范围为 -128 至 127。无符号范围为 0 至 255。

  • BOOL、BOOLEANT 这些类型是 TINYINT(1) 的同义词。值为零则为假。非零值为真:

  • SMALLINT[(M)] [UNSIGNED] [ZEROFILL] 一个小整数。有符号范围为 -32768 至 32767。无符号范围为 0 至 65535。

  • MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL] 中型整数。有符号范围为 -8388608 至 8388607。无符号范围为 0 至 16777215。

  • INT[(M)] [UNSIGNED] [ZEROFILL] 正常大小的整数。有符号范围为 -2147483648 至 2147483647。无符号范围为 0 至 4294967295。

  • INTEGER[(M)] [UNSIGNED] [ZEROFILL]该类型是 INT 的同义词。

  • BIGINT[(M)] [UNSIGNED] [ZEROFILL] 一个大整数。有符号范围是 -9223372036854775808 至 9223372036854775807。无符号范围是 0 至 18446744073709551615。SERIAL 是 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE 的别名:

    • 所有算术运算都是使用带符号的 BIGINT 或 DOUBLE 值完成的,因此,除非使用位函数,否则不应使用大于 9223372036854775807(63 位)的无符号大整数!如果这样做,在将 BIGINT 值转换为 DOUBLE 值时,由于舍入错误,结果中的某些末位数字可能会出错:

      • 在 BIGINT 列中使用整数存储较大的无符号值时。

      • 在 MIN(col_name) 或 MAX(col_name) 中,col_name 指的是 BIGINT 列。

      • 使用操作数(+、-、* 等)时,两个操作数都是整数。

    • 在 BIGINT 列中存储精确整数值时,可以使用字符串存储。在这种情况下,MySQL 会执行字符串到数字的转换,中间不涉及双精度表示。

    • 当两个操作数都是整数值时,-、+ 和 * 运算符使用 BIGINT 运算。这意味着如果将两个大整数相乘(或将返回整数的函数的结果相乘),当结果大于 9223372036854775807 时,可能会得到意想不到的结果。

  • DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] 一个打包的 "精确" 定点数。M 是总位数(精度),D 是小数点后的位数(比例)。如果 D 为 0,数值就没有小数点或小数部分。DECIMAL 的最大位数 (M) 是 65。支持的最大小数位数 (D) 为 30。如果省略 D,默认值为 0;如果省略 M,默认值为 10。(如果指定 UNSIGNED,则不允许使用负值。从 MySQL 8.0.17 起,对于 DECIMAL 类型的列(以及任何同义词),UNSIGNED 属性已被弃用;您应该期待在未来版本的 MySQL 中删除对它的支持。对于此类列,请考虑使用简单的 CHECK 约束来代替。所有使用 DECIMAL 列进行的基本计算(+、-、*、/)的精度都是 65 位。

  • DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL] 这些类型是 DECIMAL 的同义词。提供 FIXED 同义词是为了与其他数据库系统兼容。

  • FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] 一个小的(单精度)浮点数。允许值为-3.402823466E+38 至-1.175494351E-38、0 和 1.175494351E-38 至 3.402823466E+38。这些是基于 IEEE 标准的理论限制。M 是总位数,D 是小数点后的位数。如果省略 M 和 D,数值将存储在硬件允许的范围内。单精度浮点数大约精确到小数点后 7 位。FLOAT(M,D) 是一个非标准的 MySQL 扩展。从 MySQL 8.0.17 起,该语法已被弃用,预计未来版本的 MySQL 将不再支持该语法。UNSIGNED(如果指定)不允许使用负值。从 MySQL 8.0.17 起,对于 FLOAT 类型的列(以及任何同义词),UNSIGNED 属性已被弃用,您应期待在未来版本的 MySQL 中删除对它的支持。使用 FLOAT 可能会带来一些意想不到的问题,因为 MySQL 中的所有计算都是以双精度进行的。请参阅第 B.3.4.7 节 "解决无匹配行的问题"。

  • FLOAT(p) [UNSIGNED] [ZEROFILL] 一个浮点数。p 表示精度(位),但 MySQL 使用该值只是为了确定生成的数据类型是使用 FLOAT 还是 DOUBLE。如果 p 在 0 到 24 之间,数据类型将变为 FLOAT,没有 M 或 D 值。如果 p 在 25 到 53 之间,数据类型将变为 DOUBLE,不含 M 或 D 值。结果列的范围与本节前面描述的单精度 FLOAT 或双精度 DOUBLE 数据类型的范围相同。如果指定 UNSIGNED,则不允许使用负值。从 MySQL 8.0.17 起,对于 FLOAT 类型的列(以及任何同义词),UNSIGNED 属性已被弃用,您应该期待在未来版本的 MySQL 中删除对它的支持。请考虑对此类列使用简单的 CHECK 约束。

  • DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] 一个正常大小(双精度)的浮点数。允许值为-1.7976931348623157E+308 至 -2.2250738585072014E-308、0 和 2.2250738585072014E-308 至 1.7976931348623157E+308。这些是基于 IEEE 标准的理论限制。M 是总位数,D 是小数点后的位数。如果省略 M 和 D,数值将存储在硬件允许的范围内。双精度浮点数大约精确到小数点后 15 位。DOUBLE(M,D) 是一个非标准的 MySQL 扩展。从 MySQL 8.0.17 起,该语法已被弃用,预计未来版本的 MySQL 将不再支持该语法。UNSIGNED(如果指定)不允许使用负值。从 MySQL 8.0.17 起,对于 DOUBLE 类型的列(以及任何同义词),UNSIGNED 属性已被弃用,您应期待在未来版本的 MySQL 中删除对它的支持。请考虑对此类列使用简单的 CHECK 约束。

  • DOUBLE PRECISION[(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL] 这些类型是 DOUBLE 的同义词。例外: 如果启用了 REAL_AS_FLOAT SQL 模式,REAL 就是 FLOAT 而不是 DOUBLE 的同义词。

mysql> SELECT IF(0, 'true', 'false');
+------------------------+
| IF(0, 'true', 'false') |
+------------------------+
| false                  |
+------------------------+

mysql> SELECT IF(1, 'true', 'false');
+------------------------+
| IF(1, 'true', 'false') |
+------------------------+
| true                   |
+------------------------+

mysql> SELECT IF(2, 'true', 'false');
+------------------------+
| IF(2, 'true', 'false') |
+------------------------+
| true                   |
+------------------------+

不过,如图所示,TRUE 和 FALSE 分别只是 1 和 0 的别名:

mysql> SELECT IF(0 = FALSE, 'true', 'false');
+--------------------------------+
| IF(0 = FALSE, 'true', 'false') |
+--------------------------------+
| true                           |
+--------------------------------+

mysql> SELECT IF(1 = TRUE, 'true', 'false');
+-------------------------------+
| IF(1 = TRUE, 'true', 'false') |
+-------------------------------+
| true                          |
+-------------------------------+

mysql> SELECT IF(2 = TRUE, 'true', 'false');
+-------------------------------+
| IF(2 = TRUE, 'true', 'false') |
+-------------------------------+
| false                         |
+-------------------------------+

mysql> SELECT IF(2 = FALSE, 'true', 'false');
+--------------------------------+
| IF(2 = FALSE, 'true', 'false') |
+--------------------------------+
| false                          |
+--------------------------------+

由于 2 既不等于 1 也不等于 0,所以后两个语句显示了所示结果。

整数类型(精确值)--INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT

MySQL 支持 SQL 标准整数类型 INTEGER(或 INT)和 SMALLINT。作为标准的扩展,MySQL 还支持 TINYINT、MEDIUMINT 和 BIGINT 整数类型。下表显示了每种整数类型所需的存储空间和范围。

类型

存储(Bytes)

最小值(有符号)

最小值(无符号)

最大值(有符号)

最大值(无符号)

TINYINT

1

-128

0

127

255

SMALLINT

2

-32768

0

32767

65535

MEDIUMINT

3

-8388608

0

8388607

16777215

INT

4

-2147483648

0

2147483647

4294967295

BIGINT

8

-263

0

263-1

264-1

定点类型(精确值) - DECIMAL, NUMERIC

DECIMAL 和 NUMERIC 类型存储精确的数值数据值。当需要保持精确度(例如货币数据)时,就会使用这些类型。在 MySQL 中,NUMERIC 与 DECIMAL 一样实现,因此以下关于 DECIMAL 的说明同样适用于 NUMERIC。

MySQL 以二进制格式存储 DECIMAL 值。请参见 "精确数学"。

在 DECIMAL 列声明中,可以指定(通常也会指定)精度和比例。例如:

salary DECIMAL(5,2)

在本例中,5 是精度,2 是刻度。精度表示存储值的有效位数,刻度表示小数点后可存储的位数。

标准 SQL 要求 DECIMAL(5,2) 能够存储任何包含五位数和两位小数的值,因此可以存储在工资列中的值范围为 -999.99 至 999.99。

在标准 SQL 中,语法 DECIMAL(M) 等同于 DECIMAL(M,0)。同样,语法 DECIMAL 也等同于 DECIMAL(M,0),允许实现决定 M 的值。MySQL 支持这两种不同形式的 DECIMAL 语法。M 的默认值是 10。

如果刻度为 0,则 DECIMAL 值不包含小数点或小数部分。

DECIMAL 的最大位数是 65,但给定 DECIMAL 列的实际范围可能受给定列的精度或比例限制。当指定列的数值小数点后的位数超过指定比例所允许的位数时,该数值将转换为该比例。(精确的行为取决于操作系统,但一般来说,其效果是截断到允许的位数)。

浮点类型(近似值) - FLOAT, DOUBLE

FLOAT 和 DOUBLE 类型表示近似数值数据值。MySQL 使用 4 个字节表示单精度值,使用 8 个字节表示双精度值。

对于 FLOAT,SQL 标准允许在括号中的关键字 FLOAT(即 FLOAT(p))后以比特为单位可选地指定精度(但不包括指数范围)。MySQL 也支持这种可选的精度指定,但 FLOAT(p) 中的精度值仅用于确定存储大小。精度从 0 到 23 的结果是 4 字节单精度 FLOAT 列。精度从 24 到 53 的结果是 8 字节双精度 DOUBLE 列。

MySQL 允许使用非标准语法: FLOAT(M,D) 或 REAL(M,D) 或 DOUBLE PRECISION(M,D)。这里,(M,D) 表示比值最多可以存储 M 位数,其中 D 位数可以在小数点后。例如,定义为 FLOAT(7,4) 的列显示为 -999.9999。MySQL 在存储数值时会执行四舍五入,因此如果在 FLOAT(7,4) 列中插入 999.00009,大致结果就是 999.0001。

从 MySQL 8.0.17 起,非标准的 FLOAT(M,D) 和 DOUBLE(M,D) 语法已被弃用,预计未来版本的 MySQL 将取消对它的支持。

由于浮点数值是近似值,而不是作为精确值存储的,因此在比较中将它们作为精确值处理可能会导致问题。此外,浮点数还受平台或实现的影响。更多信息,请参见第 B.3.4.8 节 "浮点数值的问题"。

为获得最大的可移植性,需要存储近似数值数据值的代码应使用 FLOAT 或 DOUBLE PRECISION(不指定精度或位数)。

位数值类型 - BIT

BIT 数据类型用于存储比特值。BIT(M) 类型可以存储 M 位数值。M 的范围从 1 到 64。

要指定位值,可以使用 b'value'符号。value 是用 0 和 1 写成的二进制值。例如,b'111' 和 b'10000000' 分别表示 7 和 128。请参见第 11.1.5 节 "位值字面形式"。

如果为 BIT(M) 列赋值的长度小于 M 位,则该值的左侧会填充 0。例如,为 BIT(6) 列赋值 b'101' 实际上等同于赋值 b'000101'。

NDB 集群。 给定 NDB 表中使用的所有 BIT 列的最大组合大小不得超过 4096 位。

数字类型属性

MySQL 支持一种扩展,可在整数数据类型的基本关键字后的括号中指定该类型的显示宽度。例如,INT(4) 指定一个显示宽度为四位数的 INT。应用程序可以使用这个可选的显示宽度,通过在宽度小于为列指定的宽度的整数值的左侧添加空格来显示它们。(也就是说,这个宽度会出现在随结果集返回的元数据中。是否使用由应用程序决定)。

显示宽度不会限制列中可存储的数值范围。它也不会阻止正确显示比列显示宽度更宽的值。例如,指定为 SMALLINT(3) 的列的通常 SMALLINT 范围为 -32768 至 32767,超出三位数允许范围的值将使用三位以上的数字完整显示。

与可选(非标准)ZEROFILL 属性结合使用时,默认的空格填充将被零取代。例如,对于声明为 INT(4) ZEROFILL 的列,5 的值将被检索为 0005。

注意:

对于表达式或 UNION 查询中涉及的列,ZEROFILL 属性将被忽略。

如果在具有 ZEROFILL 属性的整数列中存储大于显示宽度的值,当 MySQL 为某些复杂的连接生成临时表时,可能会遇到问题。在这些情况下,MySQL 假定数据值适合列显示宽度。

从 MySQL 8.0.17 起,数字数据类型的 ZEROFILL 属性已被弃用,整数数据类型的显示宽度属性也是如此。预计未来版本的 MySQL 将取消对 ZEROFILL 和整数数据类型显示宽度的支持。请考虑使用其他方法来产生这些属性的效果。例如,应用程序可以使用 LPAD() 函数将数字归零到所需的宽度,也可以将格式化后的数字存储在 CHAR 列中。

所有整数类型都可以有一个可选的(非标准)UNSIGNED 属性。无符号类型可用于只允许在列中使用非负数,或需要更大的列上限数值范围。例如,如果 INT 列为 UNSIGNED,则列的范围大小不变,但其端点向上移动,从 -2147483648 和 2147483647 到 0 和 4294967295。

浮点和定点类型也可以使用 UNSIGNED。与整数类型一样,该属性可防止在列中存储负值。与整数类型不同,列值的上限范围保持不变。从 MySQL 8.0.17 起,对于 FLOAT、DOUBLE 和 DECIMAL(以及任何同义词)类型的列,UNSIGNED 属性已被弃用,您应期待在未来的 MySQL 版本中删除对它的支持。请考虑对此类列使用简单的 CHECK 约束。

如果为数字列指定 ZEROFILL,MySQL 会自动添加 UNSIGNED 属性。

整数或浮点数据类型可以具有 AUTO_INCREMENT 属性。向索引 AUTO_INCREMENT 列插入 NULL 值时,该列将被设置为下一个序列值。通常是 value+1,其中 value 是表中当前列的最大值。(AUTO_INCREMENT 序列以 1 开始)。

除非启用了 NO_AUTO_VALUE_ON_ZERO SQL 模式,否则在 AUTO_INCREMENT 列中存储 0 与存储 NULL 的效果相同。

插入 NULL 以生成 AUTO_INCREMENT 值要求列声明为 NOT NULL。如果列已声明为 NULL,则插入 NULL 会存储一个 NULL。在 AUTO_INCREMENT 列中插入任何其他值时,该列将被设置为该值,并重置序列,以便下一个自动生成的值从插入的值开始依次产生。

AUTO_INCREMENT 列不支持负值。

CHECK 约束不能引用具有 AUTO_INCREMENT 属性的列,也不能将 AUTO_INCREMENT 属性添加到用于 CHECK 约束的现有列中。

从 MySQL 8.0.17 起,对 FLOAT 和 DOUBLE 列的 AUTO_INCREMENT 支持已被弃用;您应该期待它在 MySQL 的未来版本中被移除。请考虑删除此类列的 AUTO_INCREMENT 属性,或将其转换为整数类型。

超出范围和溢出处理

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

  • If strict SQL mode is enabled, MySQL rejects the out-of-range value with an error, and the insert fails, in accordance with the SQL standard.

  • 如果启用了严格 SQL 模式,根据 SQL 标准,MySQL 会拒绝超出范围的值,并显示错误,插入失败。

  • 如果未启用限制模式,MySQL 会将该值剪辑到列数据类型范围的相应端点,并存储结果值。当超出范围的值分配给整数列时,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)

在未启用严格 SQL 模式的情况下,会出现带警告的剪切:

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 表、LOAD DATA、UPDATE 和多行 INSERT 语句,由于剪切而发生的列赋值转换会被报告为警告。在严格模式下,这些语句会失败,部分或全部值不会插入或更改,具体取决于表是否为事务表以及其他因素。详情请参阅第 7.1.11 节 "服务器 SQL 模式"。

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

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

在这种情况下,为使操作成功,请将数值转换为无符号值;

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 模式,则会发生错误,列保持不变。

沉浸于现实的忙碌之中,没有时间和精力思念过去,成功也就不会太远了。——雷音
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号