类型 | 字节数 | 带符号范围 | 无符号范围 |
---|---|---|---|
tinyint | 1 | [-128, 127] | [0, 255] |
smallint | 2 | [-32768, 32767] | [0, 65535] |
mediumint | 3 | [-8388608, 8388607] | [0, 16777215] |
int | 4 | [-2147483648, 214748367] | [0, 4294967295] |
bigint | 8 | [-9223372036854775808, 9223372036854775807] | [18446744073709551615] |
注入数据库的数字不在类型的范围内,MySQL拦截
整型默认是有符号的,在类型后面加上关键字unsigned
,说明某个字段是无符号的
bit位字段类型,可以指定有多少个比特位,最大是64位,最小是1位。
create table t1( flag bit(8)) #example
bit后括号中的数字表示一共有多少个比特位,不显式指明默认为1
create table t1( flag bit) #该表有一列, 数据类型为1个比特位
bit位字段也是有范围的,这取决于bit的位数,如bit(8)的范围是[0, 255] (全0到全1
),而bit(1)只能表示0或1。
bit位字段以ASCII对应的值显示,所以对于一些较小的值,可能对应无法显示的ascii码,也就显示不出来了。
float[(m, d)][unsigned] #[]为可选项
m表示显示长度(整数和小数的总位数),d表示小数精确位数,unsigned可以指定为无符号
float占4个字节
float的m和d可以不显式地指定
m的最大值为255,d的最大值为30
示例:
create table t3(score, float(4, 2));
float(4, 2)
表示的范围是:[-99.99, 99.99]
mysql> create table t3( name varchar(20), score float(4, 2) );
Query OK, 0 rows affected (0.03 sec)
mysql> desc t3;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(20) | YES | | NULL | |
| score | float(4,2) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into t3 values ('张三', 99.99);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3 values ('李四', -99.99);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3 values ('王五', 59.87349);
Query OK, 1 row affected (0.00 sec)
mysql> insert into t3 values ('赵六', 99.996);
ERROR 1264 (22003): Out of range value for column 'score' at row 1
mysql> insert into t3 values ('赵六', 99.994);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t3;
+--------+--------+
| name | score |
+--------+--------+
| 张三 | 99.99 |
| 李四 | -99.99 |
| 王五 | 59.87 |
| 赵六 | 99.99 |
+--------+--------+
4 rows in set (0.00 sec)
MySQL在保存浮点数时会四舍五入,如demo中59.87349存入float(4, 2)类型的列中,因为精确到小数点后2位,所以会保存为59.87。四舍五入有时也会影响越界问题,如demo中的99.996,四舍五入后是100.00,超过数据范围,无法插入;而99.994四舍五入后是99.99,可以插入。
float(4, 2) unsigned
表示的范围是:[00.00(0), 99.99]
decimal是精度更高的浮点数
decimal(m, d)[unsigned]
mysql> create table t4(
-> f float(16,8),
-> d decimal(16,8)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> desc t4;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| f | float(16,8) | YES | | NULL | |
| d | decimal(16,8) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into t4 (f, d) values (12345678.12345678, 12345678.12345678);
Query OK, 1 row affected (0.01 sec)
mysql> select * from t4;
+-------------------+-------------------+
| f | d |
+-------------------+-------------------+
| 12345678.00000000 | 12345678.12345678 |
+-------------------+-------------------+
1 row in set (0.00 sec)
可以看到,相同长度和小数位数的float和decimal,插入相同比较大的小数,decimal的精度比float更高。因此,若想要存储高精度的数据,选择decimal更合适。
char(L)
''
mysql> create table t5(
-> subject char(2)
-> ); # subject最多存储两个字符
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t5 values('eg');
Query OK, 1 row affected (0.01 sec)
mysql> insert into t5 values('pe');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t5 values('pdd'); #3个字符,插入失败
ERROR 1406 (22001): Data too long for column 'subject' at row 1
mysql> insert into t5 values('数学'); #两个汉字也被视为两个字符,可以插入
Query OK, 1 row affected (0.00 sec)
mysql> insert into t5 values('语文');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t5 values('英语');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t5 values('生物学'); #3个汉字同样插入失败
ERROR 1406 (22001): Data too long for column 'subject' at row 1
mysql> select * from t5;
+---------+
| subject |
+---------+
| eg |
| pe |
| 数学 |
| 语文 |
| 英语 |
+---------+
5 rows in set (0.00 sec)
varchar(L)
char(L)
相同,这里的L也是字符的长度,最大字节长度是65535varchar(10)
可以表示包含0~10个字符的字符串(0个字符是空串),需要多少空间就开辟多少。关于varchar(L)
中L的范围
varchar长度可以指定0~65535,但是有1-3个字节数(根据varchar长度变化)是用于记录字符串长度的,因此有效长度的最大值是65532
当我们的表的编码是utf8时,varchar(L)
的参数L最大值是65532/3=21844
(因为utf中,一个字符占用3个字节);如果编码是gbk,varchar(L)
的参数L最大是65532/2=32766
(因为gbk中,一个字符占用2字节)
mysql> create table t6 (
-> content varchar(21844)
-> ) charset=utf8; #编码是utf8
Query OK, 0 rows affected (0.03 sec)
mysql> create table t7 ( content varchar(21845) ) charset=utf8; #越界创建失败
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
mysql> create table t7 (
-> content varchar(32766)
-> ) charset=gbk; #编码是gbk
Query OK, 0 rows affected (0.03 sec)
mysql> create table t8 ( content varchar(32767) ) charset=gbk; #越界创建失败
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
char和varchar的区别
char是固定长度字符串,规定长度为多少,创建时就开辟多大的空间,类比C/C++中的数字char[N]
varchar是变长字符串,规定的是最大字符串长度,创建时只开辟需要的空间大小,只要不超过最大长度,类比C++中的std::string
同在utf8编码下具体存储区别:
存储字符串 | char(8)占用字节数 | varchar(8)占用字节数 |
---|---|---|
ABCD | 8*3 = 24 | 4*3 + 1 = 13 |
ABCDEFG | 8*3 = 24 | 8*3 + 1 = 25 |
ABCDEFGH | 数据超过长度 | 数据超过长度 |
mysql> create table t8( name varchar(20), birthday date, birthtime datetime, curtime timestamp );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t8 (name, birthday, birthtime) values ('张三', '2003-4-25', '2003-4-25 8:24:01');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t8 (name, birthday, birthtime) values ('李四', '2000-10-1', '2000-10-1 8:00:00');
Query OK, 1 row affected (0.01 sec)
mysql> select * from t8; #观察到MySQL自动填入curtime字段
+--------+------------+---------------------+---------------------+
| name | birthday | birthtime | curtime |
+--------+------------+---------------------+---------------------+
| 张三 | 2003-04-25 | 2003-04-25 08:24:01 | 2023-12-09 18:07:05 |
| 李四 | 2000-10-01 | 2000-10-01 08:00:00 | 2023-12-09 18:07:32 |
+--------+------------+---------------------+---------------------+
2 rows in set (0.00 sec)
mysql> update t8 set name='王五' where name='李四';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t8; #修改数据,时间戳会自动更新
+--------+------------+---------------------+---------------------+
| name | birthday | birthtime | curtime |
+--------+------------+---------------------+---------------------+
| 张三 | 2003-04-25 | 2003-04-25 08:24:01 | 2023-12-09 18:07:05 |
| 王五 | 2000-10-01 | 2000-10-01 08:00:00 | 2023-12-09 18:08:54 |
+--------+------------+---------------------+---------------------+
2 rows in set (0.00 sec)
enum: 枚举,单选类型。提供一些选项,最终定义为该类型的单元格,可从选项中选择一个作为单元值。每个选项实际存储的都是数字编号,依次是1,2,3,4…,最大是65535。
set: 集合,多选类型。提供一些选项,最终定义为该类型的单元格,可从选项中选择多个作为单元值。每个选项也有对应的数字编号,依次是1,2,4,8,16…,最多有64个选项(每个选项都是只有一个比特位为1)。
如:
set('音乐','电竞','运动')
, 1(001)对应’音乐’,2(010)对应’电竞’,4(100)对应’运动’,以此类推。
mysql> create table t9(
-> name varchar(20),
-> gender enum('男','女','未知'),
-> music set('说唱', '流行', '古典', '爵士', '其它')
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> desc t9;
+--------+---------------------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------------------------------------+------+-----+---------+-------+
| name | varchar(20) | YES | | NULL | |
| gender | enum('男','女','未知') | YES | | NULL | |
| music | set('说唱','流行','古典','爵士','其它') | YES | | NULL | |
+--------+---------------------------------------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> insert into t9 (name, gender, music) values ('Jcole', '男', '说唱'); #enum和set都以选项字符串值插入
Query OK, 1 row affected (0.00 sec)
mysql> insert into t9 (name, gender, music) values ('Adele', 2, '流行'); #enum以选项数字编号插入
Query OK, 1 row affected (0.01 sec)
mysql> insert into t9 (name, gender, music) values ('Jchou', 1, '说唱,流行'); #set插入多个是'XX, YY, ZZ...'
Query OK, 1 row affected (0.00 sec)
mysql> insert into t9 (name, gender, music) values ('Capper', 1, 1); #set也能以数字编号插入
Query OK, 1 row affected (0.01 sec)
mysql> insert into t9 (name, gender, music) values ('Tim', 1, 8); #8->1000->对应第四个选项'爵士'
Query OK, 1 row affected (0.00 sec)
mysql> insert into t9 (name, gender, music) values ('John', 1, 12); #12->1100->对应第三和第四个选项
Query OK, 1 row affected (0.01 sec)
mysql> select * from t9;
+--------+--------+---------------+
| name | gender | music |
+--------+--------+---------------+
| Jcole | 男 | 说唱 |
| Adele | 女 | 流行 |
| Jchou | 男 | 说唱,流行 |
| Capper | 男 | 说唱 |
| Tim | 男 | 爵士 |
| John | 男 | 古典,爵士 |
+--------+--------+---------------+
6 rows in set (0.00 sec)
enum和set的查找
mysql> select * from t9;
+--------+--------+---------------+
| name | gender | music |
+--------+--------+---------------+
| Jcole | 男 | 说唱 |
| Adele | 女 | 流行 |
| Jchou | 男 | 说唱,流行 |
| Capper | 男 | 说唱 |
| Tim | 男 | 爵士 |
| John | 男 | 古典,爵士 |
+--------+--------+---------------+
6 rows in set (0.00 sec)
mysql> select * from t9 where gender = '男';
+--------+--------+---------------+
| name | gender | music |
+--------+--------+---------------+
| Jcole | 男 | 说唱 |
| Jchou | 男 | 说唱,流行 |
| Capper | 男 | 说唱 |
| Tim | 男 | 爵士 |
| John | 男 | 古典,爵士 |
+--------+--------+---------------+
5 rows in set (0.00 sec)
mysql> select * from t9 where gender = 0;
Empty set (0.00 sec)
mysql> select * from t9 where gender = 2;
+-------+--------+--------+
| name | gender | music |
+-------+--------+--------+
| Adele | 女 | 流行 |
+-------+--------+--------+
1 row in set (0.00 sec)
mysql> select * from t9 where music = '说唱';
+--------+--------+--------+
| name | gender | music |
+--------+--------+--------+
| Jcole | 男 | 说唱 |
| Capper | 男 | 说唱 |
+--------+--------+--------+
2 rows in set (0.00 sec)
mysql> select * from t9 where music = 3;
+-------+--------+---------------+
| name | gender | music |
+-------+--------+---------------+
| Jchou | 男 | 说唱,流行 |
+-------+--------+---------------+
1 row in set (0.00 sec)
mysql> select * from t9 where find_in_set('说唱', music); #find_in_set能找到包含sub的
+--------+--------+---------------+
| name | gender | music |
+--------+--------+---------------+
| Jcole | 男 | 说唱 |
| Jchou | 男 | 说唱,流行 |
| Capper | 男 | 说唱 |
+--------+--------+---------------+
3 rows in set (0.00 sec)
mysql> select * from t9 where find_in_set('说唱', music) and find_in_set('流行', music);
+-------+--------+---------------+
| name | gender | music |
+-------+--------+---------------+
| Jchou | 男 | 说唱,流行 |
+-------+--------+---------------+
1 row in set (0.00 sec)