【MySQL】数据类型

🌈欢迎来到MySQL专栏

MySQL

一、数据类型分类

二、数值类型

大部分以整型为例

🌏tinyint类型

进行数值越界测试:

首先创建出一个表

sql 复制代码
create table if not exists t1( num tinyint );

插入四个数

sql 复制代码
insert into t1 values (-128);
insert into t1 values (127);
insert into t1 values (-1);
insert into t1 values (1);

插入越界情况:

sql 复制代码
mysql> insert into t1 values (128);
ERROR 1264 (22003): Out of range value for column 'num' at row 1

mysql> insert into t1 values (-129);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
sql 复制代码
+------+
| num  |
+------+
| -128 |
|  127 |
|   -1 |
|    1 |
+------+

在MySQL中,整型可以指定是有符号的和无符号的,默认是有符号的

建表时可以通过UNSIGNED来说明某个字段是无符号的

接下来进行无符号建表:

sql 复制代码
create table t2(num tinyint unsigned);

紧接着进行插入数据【0,255】 ------ 无符号!

sql 复制代码
mysql> insert into t2 values(-1);
ERROR 1264 (22003): Out of range value for column 'num' at row 1
mysql> insert into t2 values(0);

mysql> insert into t2 values(255);

mysql> insert into t2 values(256);
ERROR 1264 (22003): Out of range value for column 'num' at row 1

也就是说要进行插入的数据范围超过了指定的类型 ,MySQL直接拦截!不会让你插入~

注意:未来在设置数据类型的时候,提供了这么多大小不一的整数!是为了满足应用场景和节省资源之间做平衡! 存年龄的话,就用无符号的tinyint就足够了

所以MySQL中,一般而言,数据类型本身也是一种约束(约束使用者)! 倒逼程序员尽可能进行正确的插入

  • 能保证数据库中的数据是有预期的,完整的!

🌏bit类型

基本语法:

bit[(M)] : 位字段类型。M表示每个值的位数,范围从1到64。如果M被忽略,默认为1。

创建一个表,位字段设置为1

sql 复制代码
create table if not exists t3( id int, online bit(1) );
sql 复制代码
insert into t3 values(123, 1);
insert into t3 values(123, 0);
insert into t3 values(124, 2);
ERROR 1406 (22001): Data too long for column 'online' at row 1

因为此时比特位为1位,只能插入0, 1 ,插入其他值都不符合会直接报错

但我们发现为什么插入的online的值不显示呢?

  • 这里是按照ascll码值去显示的,只是当前的ascll值是不可显示的!才看不见
sql 复制代码
+------+--------+
| id   | online |
+------+--------+
|  123 |       |
|  124 |        |
+------+--------+

想要看见online的值可以按照十进制的方式进行打印

sql 复制代码
mysql> select id, hex(online) from t3;
+------+-------------+
| id   | hex(online) |
+------+-------------+
|  123 | 1           |
|  124 | 0           |
+------+-------------+

我们往里插入65和97,看看它是否会显示出来 A 和 a ?

sql 复制代码
+------+--------+
| id   | online |
+------+--------+
|  123 |       |
|  124 |        |
|  124 |       |
|  124 |  A     |
|  124 |  a     |
+------+--------+

🌏小数类型

🔥float

语法:

sql 复制代码
decimal(m, d) [unsigned] 

定点数m指定长度 ,d表示小数点的位数

小数:float(4,2)表示的范围是-99.99 ~ 99.99,MySQL在保存值时会进行四舍五入

sql 复制代码
mysql> insert into t4 (id, salary) values (1, 99.99);

mysql> insert into t4 (id, salary) values (1, -99.99);

mysql> insert into t4 (id, salary) values (1, 100); ❌️
mysql> insert into t4 (id, salary) values (1, -100);❌️
mysql> insert into t4 (id, salary) values (1, 99.998);❌️

mysql> insert into t4 (id, salary) values (1, 99.991);
mysql> insert into t4 (id, salary) values (1, 99.994);
mysql> insert into t4 (id, salary) values (1, -99.94);
mysql> insert into t4 (id, salary) values (1, 10.0);

可以看出存99.994会进行四舍五入 去存(前提是四舍五入后也要符合范围,不然插入失败),-99.94同理;存 10.0 会帮我们把精度补齐到两位;

sql 复制代码
+------+--------+
| id   | salary |
+------+--------+
|    1 |  99.99 |
|    1 | -99.99 |
|    1 |  99.99 |
|    1 |  99.99 |
|    1 |  10.00 |
|    1 | -99.94 |
+------+--------+

如果定义的是float(4,2) unsigned 这时,因为把它指定为无符号的数,范围是 【0 ~ 99.99】

sql 复制代码
mysql> create table tt7(id int, salary float(4,2) unsigned);
mysql> insert into tt7 values(100, -0.1);❌️//直接认为超出有效范围了

mysql> insert into tt7 values(100, -0);✅️
mysql> insert into tt7 values(100, 99.99);✅️

精度损失:

sql 复制代码
mysql> insert into t5 (id, salary) values (1, 122334455.2);

mysql> insert into t5 (id, salary) values (1, 1223344.1112);

mysql> select *from t5;
+------+-----------+
| id   | salary    |
+------+-----------+
|    1 | 122334000 |
|    1 |   1223340 |
+------+-----------+

🔥decimal

decimal可以有效的规避精度的损失!

sql 复制代码
decimal(m, d) [unsigned] 

定点数m指定长度,d表示小数点的位数

  • decimal(5,2) 表示的范围是 -999.99 ~ 999.99
  • decimal(5,2) unsigned 表示的范围 0 ~ 999.99

decimal和float很像,但是有区别;float和decimal表示的精度不一样

sql 复制代码
mysql> insert into t6 (f1, f2) values (23.12345612, 23.12345612);

mysql> select * from t6;
+-------------+--------------+
| f1          | f2           |
+-------------+--------------+
| 23.12345695 |  23.12345612 |
+-------------+--------------+

发现decimal的精度更准确 ,因此如果我们希望某个数据表示高精度,选择decimal

  • float表示的精度大约是7位

decimal整数最大位数m为65。支持小数最大位数d是30。如果d被省略,默认为0,如果m被省略,默认是10

🌏字符串类型

🔥char

char(L): 固定长度字符串 ,L是可以存储的长度,单位为字符,最大长度值可以为255

  • 一个中文汉字就是一个字符!

创表:

sql 复制代码
mysql> create table if not exists t7(
    -> id int,
    -> name char(2)
    -> );
sql 复制代码
mysql> insert into t7 (id, name) values(11, 'a');

mysql> insert into t7 (id, name) values(11, 'A');

mysql> insert into t7 (id, name) values(11, 'Bb');

mysql> insert into t7 (id, name) values(11, 'Cc');

mysql> insert into t7 (id, name) values(11, 'CcA');❌️

mysql> insert into tt9 values(101, '中国');
mysql> insert into tt9 values(101, '中国人');❌️

+------+------+
| id   | name |
+------+------+
|   11 | a    |
|   11 | A    |
|   11 | Bb   |
|   11 | Cc   |
|   101| 中国 |
+------+------+

char(2) 表示可以存放两个字符 ,可以是字母或汉字,但是不能超过2个, 最多只能是255

sql 复制代码
mysql> create table tt10(id int ,name char(256));

ERROR 1074 (42000): Column length too big for column 'name' (max = 255); use BLOB or TEXT instead

🔥varchar

varchar(L): 可变长度字符串 ,L表示字符长度,最大长度65535个字节(不是字符)

举例:

sql 复制代码
mysql> insert into t8 (id, name) values(123, '中国人能飞!');
mysql> insert into t8 (id, name) values(123, '中国人能飞!!');❌️
+------+--------------------+
| id   | name               |
+------+--------------------+
|  123 | 中国人能飞!       |
+------+--------------------+
sql 复制代码
mysql> alter table t8 modify name varchar(65535);

ERROR 1074 (42000): Column length too big for column 'name' (max = 21845); use BLOB or TEXT instead

那么char和varchar有什么区别呢??

varchar(len),len到底是多大,这个len值,和表的编码密切相关:

  • varchar长度可以指定为0到65535之间的值,但是有1 - 3 个字节用于记录数据大小 ,所以说有效字节数是65532

  • 当我们的表的编码是utf8时,varchar(n)的参数n最大值是65532/3=21844因为utf中,一个字符占用3个字节

  • 如果编码是gbk,varchar(n)的参数n最大是65532/2=32766(因为gbk中,一个字符占用2字节)。

验证了utf8确实是不能超过21844

sql 复制代码
mysql> create table tt11(name varchar(21845));❌️
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 tt11(name varchar(21844));

如果该表还有其他字段,可能这个值会更小

🆚char和varchar比较

varchar多申请一个字节来保存该数字大小!

如何选择定长或变长字符串?

  • 如果数据确定长度都一样,就使用定长 (char),比如:身份证,手机号,md5
  • 如果数据长度有变化,就使用变长 (varchar), 比如:名字,地址,但是你要保证最长的能存的进去。
  • 定长的磁盘空间比较浪费,但是效率高。
  • 变长的磁盘空间比较节省,但是效率低。
  • 定长 的意义是,直接开辟好对应的空间
  • 把的意义是,在不超过自定义范围的情况下,用多少,开辟多少

🔥日期和时间类型

常用的日期有如下三个:

  • date :日期 'yyyy-mm-dd' ,占用三字节
  • datetime 时间日期格式 'yyyy-mm-dd HH:ii:ss' 表示范围从 1000 到 9999 ,占用八字节
  • timestamp :时间戳 ,从1970年开始的 yyyy-mm-dd HH:ii:ss 格式和 datetime 完全一致,占用四字节

上手:

sql 复制代码
mysql> create table if not exists t9(
    -> t1 date,
    -> t2 datetime,
    -> t3 timestamp
    -> );
    
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| t1    | date      | YES  |     | NULL              |                             |
| t2    | datetime  | YES  |     | NULL              |                             |
| t3    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+

对timestamp做插入或者更新, timestamp会自动更新为当前的时间!

我们能插入修改的只有datetime 和 date

  • 添加数据时,时间戳自动补上当前时间
  • 更新数据,时间戳会更新成当前时间
sql 复制代码
mysql> insert into t9 (t1, t2) values('1997-7-1','2008-8-8 12:1:1');

mysql> select * from t9;
+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 1997-07-01 | 2008-08-08 12:01:01 | 2026-10-21 10:47:27 |
+------------+---------------------+---------------------+

mysql> update t9 set t1='1999-10-26'; //更新t1时间

mysql> select * from t9;
+------------+---------------------+---------------------+
| t1         | t2                  | t3                  |
+------------+---------------------+---------------------+
| 1999-10-26 | 2008-08-08 12:01:01 | 2026-10-21 10:57:10 |
+------------+---------------------+---------------------+
1 row in set (0.00 sec)

🔥enum和set

语法:

sql 复制代码
enum:枚举,"单选"类型;
enum('选项1','选项2','选项3',...);

该设定只是提供了若干个选项的值,最终一个单元格中,实际只存储了其中一个值;而且出于效率考虑,这些值实际存储的是"数字" ,因为这些选项的每个选项值依次对应如下数字:1,2,3,...最多65535个;当我们添加枚举值时,也可以添加对应的数字编号

sql 复制代码
set:集合,"多选"类型;
set('选项值1','选项值2','选项值3', ...);

该设定只是提供了若干个选项的值,最终一个单元格中,设计可存储了其中任意多个值;而且出于效率考虑,这些值实际存储的是"数字",因为这些选项的每个选项值依次对应如下数字:1,2,4,8,16,32,...最多64个

案例:

有一个调查表votes,需要调查人的喜好, 比如(登山,游泳,篮球,武术)中去选择(可以多选 ),(男,女)单选

sql 复制代码
mysql> create table votes(
    -> username varchar(30),
    -> gender enum('男', '女'),
    -> hobby set("代码", "打篮球", "游泳", "足球", "乒乓球")
    -> );
    
+----------+---------------------------------------------------------+------+-----+---------+-------+
| Field    | Type                                                    | Null | Key | Default | Extra |
+----------+---------------------------------------------------------+------+-----+---------+-------+
| username | varchar(30)                                             | YES  |     | NULL    |       |
| gender   | enum('男','女')                                         | YES  |     | NULL    |       |
| hobby    | set('代码','打篮球','游泳','足球','乒乓球')             | YES  |     | NULL    |       |
+----------+---------------------------------------------------------+------+-----+---------+-------+
sql 复制代码
mysql> insert into votes values('张飞', '男', '代码');

mysql> insert into votes values('刘备', '男', '爬山');

mysql> insert into votes values('关羽', '男', '健身');

mysql> insert into votes values('关羽', '未知', '健身'); ❌️

如果爱好选择多个

sql 复制代码
mysql> insert into votes values('张飞', '男', '代码,游泳');

mysql> select * from votes;
+----------+--------+---------------+
| username | gender | hobby         |
+----------+--------+---------------+
| 张飞     | 男     | 代码          |
| 刘备     | 男     | 爬山          |
| 关羽     | 男     | 健身          |
| 张飞     | 男     | 代码,游泳     |
+----------+--------+---------------+

如果是以数字作为插入,这个数字绝对不是对应枚举里的下标 。而是

sql 复制代码
000001:对应代码
000010:对应打篮球
000011:前两个爱好我们都设置
000100:游泳
...
sql 复制代码
mysql> insert into votes values('张飞', 1, 0);

mysql> insert into votes values('张飞', 1, 1);

mysql> insert into votes (username) values('卢本伟');

mysql> select * from votes;
+-----------+--------+---------------+
| username  | gender | hobby         |
+-----------+--------+---------------+
| 张飞      | 男     |               |
| 张飞      | 男     | 打篮球        |
| 卢本伟    | NULL   | NULL          |
+-----------+--------+---------------+

注意NULL 和 '' 不一样!NULL是空,什么都没有,但''是空串!

  • NULL是我没有建行卡,''是有这张卡,但是里面没钱!
sql 复制代码
insert into votes values('张飞', 1, 63);

张飞      | 男     | 打篮球,足球,代码,健身,游泳,爬山       

也就是把6个比特位全部置1,对应是63

接下来我们对这个表进行查找操作!

先找出所有男的

sql 复制代码
mysql> select * from votes where gender='男';

+----------+--------+----------------------------------------------+
| username | gender | hobby                                        |
+----------+--------+----------------------------------------------+
| 张飞     | 男     | 代码                                         |
| 刘备     | 男     | 爬山                                         |
| 关羽     | 男     | 健身                                         |
| 张飞     | 男     | 代码,游泳                                    |
| 张飞     | 男     |                                              |
| 张飞     | 男     | 打篮球                                       |
| 张飞     | 男     | 打篮球,足球                                  |
| 张飞     | 男     | 代码                                         |
| 张飞     | 男     | 打篮球,足球,代码,健身,游泳,爬山              |
+----------+--------+----------------------------------------------+

接下来找出喜欢羽毛球的人

sql 复制代码
mysql> select * from votes where hobby='代码';
+----------+--------+--------+
| username | gender | hobby  |
+----------+--------+--------+
| 张飞     | 男     | 代码   |
| 张飞     | 男     | 代码   |
+----------+--------+--------+

但是这种只能找出只喜欢代码这一个爱好的人,多个爱好(包括代码)的人却找不到!

能找出爱好中有代码的吗?能! 只不过也有缺点,它是严格匹配的!

sql 复制代码
mysql> select * from votes where hobby='代码,游泳';
+----------+--------+---------------+
| username | gender | hobby         |
+----------+--------+---------------+
| 张飞     | 男     | 代码,游泳     |
+----------+--------+---------------+

所以引出了:集合查询使用find_ in_ set函数

sql 复制代码
find_in_set(sub,str_list) 
  • 如果 sub 在 str_list 中,则返回下标 ;如果不在,返回0;
  • str_list 用逗号分隔的字符串
sql 复制代码
mysql> select find_in_set('a', 'a,b,c');
+---------------------------+
| find_in_set('a', 'a,b,c') |
+---------------------------+
|                         1 |
+---------------------------+

mysql> select find_in_set('a,c', 'a,b,c');
+-----------------------------+
| find_in_set('a,c', 'a,b,c') |
+-----------------------------+
|                           0 |
+-----------------------------+

find_ in_ set只能在一个集合里查找某一个元素是否存在!返回0说明不存在,返回非0则是对应集合的下标!

sql 复制代码
mysql> select * from votes where find_in_set('游泳', hobby);

+----------+--------+----------------------------------------------+
| username | gender | hobby                                        |
+----------+--------+----------------------------------------------+
| 张飞     | 男     | 代码,游泳                                    |
| 张飞     | 男     | 打篮球,足球,代码,健身,游泳,爬山              |
+----------+--------+----------------------------------------------+

📢写在最后

接下来登场的是 表的约束!

相关推荐
漫步人生走在路上44 分钟前
外贸SEO中的品牌词与产品词策略:大卖家和小卖家的不同打法
大数据·javascript·网络·数据库·人工智能·搜索引擎
泡海椒1 小时前
JQuick-SQL LIMIT 分页:限制行数与偏移查询
数据库·sql
讳疾忌医丶1 小时前
编译器眼中的 C++ 循环:从指针别名、IEEE 754 结合律到 SIMD 语义证明
开发语言·c++
金色熊族1 小时前
ebpf程序开发(一)--ubuntu20.04
linux·ebpf
‎ദ്ദിᵔ.˛.ᵔ₎1 小时前
Linux 线程控制
linux
2501_916008891 小时前
马甲包过审卡在哪?Ipa Guard 能做的和做不到的
android·小程序·https·uni-app·iphone·webview
叼烟扛炮1 小时前
Linux 学习笔记(八):GCC 编译器的四大阶段与链接原理
linux·笔记·学习
catino1 小时前
SQL调优
数据库·sql
猫咪很可爱1 小时前
Oracle Data Pump 导入报错 ORA-02375:字符集不一致问题分析与处理
数据库·oracle