MySQL 中的数字类型
MySQL 中数据类型常用的就三大类:
另外还包含两个没那么常用的大类:
继续之前,先来看一些单位上的约定和概念,
存储字符串时指定的类型
展示宽度/Display Width那么什么是展示宽度。展示宽度这个参数具有迷惑性,它不像 CREATE TABLE test_zero_fill
(
with_fill INT(5) UNSIGNED ZEROFILL NOT NULL PRIMARY KEY,
without_fill INT(5) UNSIGNED NOT NULL
); mysql> INSERT INTO test_zero_fill (with_fill, without_fill) VALUES (5, 5),(123456, 123456);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
另外,如果使用了 mysql> ALTER TABLE test_zero_fill ADD signed_num INT(5) signed ZEROFILL NOT NULL after without_fill;
mysql> describe test_zero_fill;
+--------------+--------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------------------+------+-----+---------+-------+
| with_fill | int(5) unsigned zerofill | NO | PRI | NULL | |
| without_fill | int(5) unsigned | NO | | NULL | |
| signed_num | int(5) unsigned zerofill | NO | | NULL | |
+--------------+--------------------------+------+-----+---------+-------+
3 rows in set (0.00 sec) 所以对于数据存储层面来说,展示宽度其实没什么用途。如果真的需要格式化,程序中能够请求 MySQL 的 meta 信息以获取到相应的展示宽度。 假如在 Node.js 中使用 mysqljs/mysql 作为数据库连接的模块,在执行请求时,其回调中返回的 connection.query("SELECT * from test_zero_fill", function(
error,
results,
fields
) {
if (error) throw error;
console.log(fields);
}); fields 中包含列的 meta 信息 FieldPacket {
catalog: 'def',
db: 'data_type',
table: 'test_zero_fill',
orgTable: 'test_zero_fill',
name: 'with_fill',
orgName: 'with_fill',
charsetNr: 63,
length: 5,
type: 3,
flags: 20579,
decimals: 0,
default: undefined,
zeroFill: true,
protocol41: true
},
FieldPacket {
catalog: 'def',
db: 'data_type',
table: 'test_zero_fill',
orgTable: 'test_zero_fill',
name: 'without_fill',
orgName: 'without_fill',
charsetNr: 63,
length: 5,
type: 3,
flags: 4129,
decimals: 0,
default: undefined,
zeroFill: false,
protocol41: true
},
FieldPacket {
catalog: 'def',
db: 'data_type',
table: 'test_zero_fill',
orgTable: 'test_zero_fill',
name: 'signed_num',
orgName: 'signed_num',
charsetNr: 63,
length: 5,
type: 3,
flags: 4193,
decimals: 0,
default: undefined,
zeroFill: true,
protocol41: true
}
] 因此,在设计表时,应该关注使用哪种具体的数据类型能够满足数据存储的需要,而不要被展示宽度所迷惑。 数字类型数字类型分为有符号 整型MySQL 中支持标准的 SQL 整型,
并且扩展了一些类型:
以下是 MySQL 中支持的整型,及其对应所需存储空间和取值范围。
具体到每种类型:
mysql> SELECT IF(0, 'true', 'false');
+------------------------+
| IF(0, 'true', 'false') |
+------------------------+
| false |
+------------------------+
mysql> SELECT IF(0 = FALSE, 'true', 'false');
+--------------------------------+
| IF(0 = FALSE, 'true', 'false') |
+--------------------------------+
| true |
+--------------------------------+
关于大整型,关键字 还记得创建表时一般需要指定一个自增的整形 ID 字段么, CREATE TABLE table_name (id INT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT)
CREATE TABLE table_name (id SERIAL PRIMARY KEY) 如果你不想要 BIGINT, CREATE TABLE table_name (id INT SERIAL DEFAULT VALUE PRIMARY KEY) 定点型DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL] 定点型数字,其中 M 表示总的位数(不包含正负号及小数点),D 表示小数位数。D 为 0 则表示没有小数部分。M 最大取值 65,默认 10;D 最大支持到 30,默认 0。所有的算术运算( DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL] 同 定点型数字存储精确的数字,用于准确性要求高的场合,比如涉及金钱。底层实现上,MySQL 使用二进制形式存储该类型的值。 通常的用法如下: salary DECIMAL(5,2) 上面示例中,salary 为一个 5 位精度两位小数的定点型。取值范围 -999.99 ~ 999.99。 因为 D 缺省时默认为 0,所以 当实际存储的值其小数大于指定的位数时,其精度会自动转换成所存储的值的精度。 浮点型区别于 DECIMAL,浮点型存储的数字是个近似值。内部存储时,MySQL 为单精度使用 4 字节(bytes),双精度使用 8 字节。 浮点型包含以下这些类型:
所以实际使用时,为了最大限度的兼容性,直接使用 BIT 类型BIT[(M)] 类型用于存储单个状态值,M 表示包含几位。默认为1,最大可取 64。 该类型的值可通过 如果赋值到该类型上的值小于 M 指定的位数,值左边会补零,比如将 b'101' 存储到类型为 BIT(6) 的列,实际会是 b'000101'。 存储的值溢出的情况将要存储的值超出数字类型的范围时,其表现跟当前设置的 SQL 模式有关。具体来说,
考察一个通过如下语句创建的表 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 |
+------+------+ 上述表现同样会出现在涉及到对列进行转换修改的一些操作上,比如 进行数字计算时如果有溢出,也会抛错,比如对于 BIGINT 其最大值为 9223372036854775807,因为 MySQL 中默认对数字类型是有符号类型,如下操作会抛错, mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)' 对于上述情况,可显式将 被操作数进行类型转换,转成无符号的 BIGINT: mysql> SELECT CAST(9223372036854775807 AS UNSIGNED) + 1;
+-------------------------------------------+
| CAST(9223372036854775807 AS UNSIGNED) + 1 |
+-------------------------------------------+
| 9223372036854775808 |
+-------------------------------------------+ 通过带上小数后,转成 DECIMAL 也能修正上面的错误,因为 DECIMAL 比整形要大, mysql> SELECT 9223372036854775807.0 + 1;
+---------------------------+
| 9223372036854775807.0 + 1 |
+---------------------------+
| 9223372036854775808.0 |
+---------------------------+ 两数相减时,其中一个为无符号数,得出的结果默认为也为无符号。所以如果想减之后结果是负数,则会抛错。 mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
除非开启了 mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
| -1 |
+-------------------------+ 总结对于整型或浮点型,可指定 对于需要精确数值的场合,使用 DECIMAL,比如涉及金钱的情况。 对于整形,展示宽度不是其存储的值范围,只用来格式化。 相关资源 |