5 数据类型
5.1 数值类型
python
create table num_types
(
bit_ bit, # 比特,最小数值类型,位类型
tinyint_ tinyint, # [-128, 127]
bool_ bool, # 0 and 1
smallint_ smallint, # [-2^15, 2^15 - 1]
int_ int, # [-2^31, 2^31 - 1]
bigint_ bigint, # [-2^63, 2^63 - 1]
float_ float, # 大小在4字节,你可以在后面接(M, D)自定义显示长度(M)和小数点后的位数(D)
double_ double, # 大小在8字节,同样可以使用(M, D)
decimal_ decimal # 一个特殊的浮点数类型,可以指定任意长度,换句话说,(M, D)可以几乎完全自定义,几乎没有限制,这在精度刚需的数据中很有用,我这里没有指定,所以实际不会显示小数
);
sql
mysql> create table num_types
-> (
-> bit_ bit,
-> tinyint_ tinyint,
-> bool_ bool,
-> smallint_ smallint,
-> int_ int,
-> bigint_ bigint,
-> float_ float,
-> double_ double,
-> decimal_ decimal
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> show create table num_types\G
*************************** 1. row ***************************
Table: num_types
Create Table: CREATE TABLE `num_types` (
`bit_` bit(1) DEFAULT NULL,
`tinyint_` tinyint DEFAULT NULL,
`bool_` tinyint(1) DEFAULT NULL,
`smallint_` smallint DEFAULT NULL,
`int_` int DEFAULT NULL,
`bigint_` bigint DEFAULT NULL,
`float_` float DEFAULT NULL,
`double_` double DEFAULT NULL,
`decimal_` decimal(10,0) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> insert into num_types (bit_, tinyint_, bool_, smallint_, int_, bigint_, float_, double_, decimal_)
-> values(
-> b'1',
-> 127,
-> true,
-> 32767,
-> -2147483648,
-> 9223372036854775807,
-> 1.23456789,
-> 1.23456789012345,
-> 999999.99
-> );
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from num_types\G
*************************** 1. row ***************************
bit_: 0x01
tinyint_: 127
bool_: 1
smallint_: 32767
int_: -2147483648
bigint_: 9223372036854775807
float_: 1.23457
double_: 1.23456789012345
decimal_: 1000000
1 row in set (0.00 sec)
-
注意:
float和double的自定义(M, D)功能其实已经在MySQL 8.0.17版本被弃用了,即便你用了也只会造成显示层面的改变,实际不会改变其存储的数值decimal的(M, D)存在物理上限,M最大为65,D最大为30,且不能超过M- 可以用
UNSIGNED来让其变成一个无符号的数 bit支持以bit(M)的形式指定长度,除非大小直接超过了65535字节- 虽然几乎所有整形都支持类似于
bit(M)的语法,但是实际意义不一样,比方说int(5)在另一个关键字zerofill的加持下表示尽量显示五位数字(如果没有这个关键字,那就没有任何意义),对标浮点数的(M, D)
-
测试一下
(M, D)与UNSIGNED,以及上一小节说过的临时表

- 这里你能看到,临时表是可以同名的,不过缺点是,如果你想现在用同名的非临时表,就只能先想办法删除/销毁这个临时表,才可以用非临时表,因为同名了,所以默认情况下会始终使用临时表


- 退出之后重进会导致临时表被销毁,此时查表就只能查到非临时表了
5.2 字符串类型
sql
create table char_types (
-- char如果没有指定数值,那么默认就是1个字符的大小
char_ char,
-- char的最大值,也就是最多连续255个字符
char_max_ char(255),
-- varchar必须指定长度
-- 实际上这不是varchar的最大值,而是估算的最大值,后续会提到
varchar_max_ varchar(16000)
-- 注意,这里我们说的是字符数!如果换算成字节,需要根据编码来实际判断
);
- 如果你尝试把
varchar指定一个比较大的数值,多半会报错,我们打个比方 - 假设现在字符集是
utf8mb4,那么一个字符要吃掉大约4字节,我们在"数值类型"说过,指定长度不能超过65535字节,那么也就是说,varchar在这种情况下最多也就存大约16,383个
字符,同时,varchar其实还会多用一些空间,有一些隐藏开销,比方说实际上varchar_max_也会占用空间,所以我这里也就填了16000


| 类型 | 本质 | 长度上限 | 性能 | 应用场景 |
|---|---|---|---|---|
char |
定长数组 | 255个字符,一般不会顶到65535字节的上限 | 性能很不错,但是缺点是一旦开辟就一定会占用对应大小的空间 | 卡号,ID号等等长度固定的数据储存 |
varchar |
变长数组 | 长度上线取决于使用的字符集 | 性能会比char差一些,因为可能要做分页或者移动什么的,但是非常能节约空间 |
长度不固定的数据存储,像是用户的评论什么的 |
- 值得一提的是,
char在没有存储有效数据的部分(一般是尾部),其实是全部填充空格的
5.3 枚举和选项
sql
create table test_enum_and_set(
name varchar(64),
-- 枚举类型
-- 和C语言的枚举类型类似,定义的时候创建索引,实际存储数字
-- 搜索的时候会找索引中对应的值
-- 使用的时候也可以直接输入数字
gender enum('xiaonanniang', 'cixiaogui', 'guzhangjiqiren'),
-- 集合类型
-- 实际上是一个位图,定义的时候会创建索引
-- 区别于enum,set类型允许存在若干个选项/值,所以用位图更加省空间
cards set('daji', 'fangyu')
);
- 插几个值
sql
mysql> insert into test_enum_and_set values('chujun', 'cixiaogui', 'daji,fangyu');
Query OK, 1 row affected (0.01 sec)
mysql> insert into test_enum_and_set values('xiaolanren', 'guzhangjiqiren', 1);
Query OK, 1 row affected (0.01 sec)
mysql> insert into test_enum_and_set values('ni', 1, 2);
Query OK, 1 row affected (0.01 sec)
- 搜一下
markdown
mysql> select * from test_enum_and_set\G
*************************** 1. row ***************************
name: chujun
gender: cixiaogui
cards: daji,fangyu
*************************** 2. row ***************************
name: xiaolanren
gender: guzhangjiqiren
cards: daji
*************************** 3. row ***************************
name: ni
gender: xiaonanniang
cards: fangyu
3 rows in set (0.00 sec)
- 可以指定字段查询
markdown
mysql> select * from test_enum_and_set where gender = 'xiaonanniang'\G
*************************** 1. row ***************************
name: ni
gender: xiaonanniang
cards: fangyu
1 row in set (0.00 sec)
- 你会发现这里其实匹配有点严格,因为只查出来只有
fangyu的行 - 所以我们可以用个函数,
find_in_set(str, strlist),如果str在strlist中,就会返回1,否则返回0 - 放在这个语境,就是挑出符合"
'daji'在cards"中的行
markdown
mysql> select * from test_enum_and_set where find_in_set('daji', cards)\G
*************************** 1. row ***************************
name: chujun
gender: cixiaogui
cards: daji,fangyu
*************************** 2. row ***************************
name: xiaolanren
gender: guzhangjiqiren
cards: daji
2 rows in set (0.00 sec)