MySQL 中的数字类型
MySQL 中数据类型常用的就三大类: SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
另外还包含两个没那么常用的大类:
继续之前,先来看一些单位上的约定和概念,
存储字符串时指定的类型
展示宽度/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> select * from test_zero_fill; +-----------+--------------+ | with_fill | without_fill | +-----------+--------------+ | 00005 | 5 | | 123456 | 123456 | +-----------+--------------+ 2 rows in set (0.00 sec) 另外,如果使用了 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(1, 'true', 'false'); +------------------------+ | IF(1, 'true', 'false') | +------------------------+ | true | +------------------------+ mysql> SELECT IF(2, 'true', 'false'); +------------------------+ | IF(2, 'true', 'false') | +------------------------+ | true | +------------------------+ 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 | +--------------------------------+
关于大整型,关键字 还记得创建表时一般需要指定一个自增的整形 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> SELECT CAST(0 AS UNSIGNED) - 1; ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)' 除非开启了 mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION'; mysql> SELECT CAST(0 AS UNSIGNED) - 1; +-------------------------+ | CAST(0 AS UNSIGNED) - 1 | +-------------------------+ | -1 | +-------------------------+ 总结对于整型或浮点型,可指定 对于需要精确数值的场合,使用 DECIMAL,比如涉及金钱的情况。 对于整形,展示宽度不是其存储的值范围,只用来格式化。 相关资源 |
