前言
上篇文章小编讲述了关于MySQL表的DDL操作,在那里我多次使用了MySQL的数据类型,但是我并没有去讲述MySQL的数据类型,想必各位读者已经很好奇MySQL的数据类型都有什么了,今天这篇文章我将会详细的去讲述MySQL的数据类型,希望可以为各位解惑。
1.数据类型以及分类
在详细说明每个数据类型之间,我先来让各位看一看MySQL中有几种数据类型以及它们的分类(只截取了比较重要的一部分,还有一些我并没有展示出来,各位读者感兴趣可以去官方网站自行学习)。
上面的类型有很多种,不过很多我们在学C语言的时候就已经感到很熟悉了,就比如数值类型中的int类型,它就是我们在C语言学习的整型,这点MySQL和C语言还是一样的,当然MySQL和C语言还是有差异的地方的,就比如文本类型的中的char,在C语言中,它代表的是字符类型,也就是'A'、'B'等等的字符;而它在MySQL代表的事一个固定长度的字符串,各位千万不要把它的定义和C语言的混为一谈。下面我将从数值类型、文本。二进制类型。时间日类类型以及string类型这几个方面,详细讲述MySQL的数据类型以及它和编程语言的异同,帮各位避开这些认知陷阱。
2.数值类型
上表就是我想要讲述的数值类型,此时我先简单的带着各位看下这个表,这个表大多数的都是和整型int相关的,之所以放到一起是因为我认为它们是有相似性的,当我讲述完其中几个以后,剩下的类型各位就可以自己去领悟了(绝对不是因为我偷懒),下面我来分别讲述一下这几种类型。
2.1.tinyint类型
通过上表,我们可以简单的知道它所代表的范围是-128到127,因为它是占据一个字节,一个字节是八个比特位,所以它可以表示2^8也就是256个不同的值(从00000000到11111111);在计算机用补码表示有符号整数时,最高位为0表示正数(0到127),最高位为1表示负数(-1到-128),其中 10000000 这个特殊编码被定义为 -128,因此整体范围就是 -128 到 127。因此它的范围就是-128到127,可能有些读者好奇它的范围真的卡的那么严吗?不要急,下面我简单的进行范围的测试(里面涉及到表的DML的知识,这是我下一篇文章要讲述的,各位读者可以先期待着)。
1.范围检测
此时我简单的建立一个表,这个表的名字是student,里面涉及学生的学号以及姓名(就这么简单就好了),下面是实现的代码(建议各位读者可以自行实现,之后再来和我的进行对照)。
create table student(name varchar(20) #代表的是姓名id tinyint
);#代表表的创建
插入边界值
此时我们可以先插入最大值试一试,因为我还没有讲述表的插入操作,所以各位知晓我的目的是把一个学生姓名为张三的,id为127;
insert into student values('张三',127);
此时可以看出插入成功了,下面我们查询我们插入的数据。同样的,这涉及到表的查询操作,我依旧不解释。
select * from student;
下面我们插入最小值试一下,插入一个姓名为李四,id为-128(有点奇怪)的数据。
insert into student values('李四',-128);
此时数据依然是插入成功了,我们依旧可以查询插入的数据。
select * from student;
插入一个不在范围内的值
此时我试着插入一个姓名为小禾,id为128的数据。
insert into student values('小禾',128);
正如我们所见,尝试插入超出 tinyint
范围(-128 到 127)的值导致了错误。这验证了整型的一个重要规则:当插入的值超出该整型定义的数值范围时,数据库系统会报错。 其他整型(如 smallint
, int
, bigint
)的核心机制与此完全相同,区别仅在于它们能容纳的范围大小不同。既然原理一致,我们就不再逐一赘述。接下来,让我们把目光转向另一种重要的数据类型——小数类型。
2.2.小数类型
1.float类型
语法:
float[(m, d)] [unsigned] : M指定显示长度,d指定小数位数,占用空间4个字节
与整型不同,float
类型在定义时需要指定两个参数,语法为 float(M, D)
。下面我来详细解释这两个参数的含义和使用规则:
参数解析
-
M
(总精度/显示宽度):代表该浮点数总共可以显示的最大数字位数(包括整数部分和小数部分的所有数字字符,不包括小数点本身和符号位)。-
例如:
128.1
包含数字1
,2
,8
,1
→ 总共 4 位数字 -
12.81
包含数字1
,2
,8
,1
→ 总共 4 位数字
-
-
D
(小数位数/标度):代表该浮点数小数点后允许的最大位数。-
例如:
128.1
的小数点后有 1 位数字 (1
) -
12.81
的小数点后有 2 位数字 (81
)
-
关键特性
-
M
和D
定义的是上限值[敲重点]:实际存储的数字位数可以少于M
,小数位数可以少于D
,但不能超过 -
float
存储的是近似值而非精确值(这一点与整型完全不同) -
数值范围极大(约 ±10^38),但精度有限(约7位有效数字)
实例演示
下面我通过一个建表实例,展示 float
类型的使用规则:
1. 创建测试表
-- 创建包含float(4,2)类型的测试表
CREATE TABLE product (name VARCHAR(20), -- 产品名称price FLOAT(4,2) -- 价格(总位数不超过4,小数位不超过2)
);
2. 插入合法数据
-- 有效数据:总位数4,小数位2
INSERT INTO product VALUES ('铅笔', 12.34); -- 数字:1,2,3,4 → 4位
-- 有效数据:总位数3<4,小数位1<2
INSERT INTO product VALUES ('橡皮', 8.5); -- 数字:8,5 → 2位(总位数不足)
-- 有效数据:边界值测试
INSERT INTO product VALUES ('笔记本', 99.99); -- 数字:9,9,9,9 → 4位
3. 插入非法数据(验证限制)
-- 超出总位数限制(5>4)
INSERT INTO product VALUES ('钢笔', 100.00);
-- 错误:总位数5 (1,0,0,0,0) > 4
-- 超出小数位限制(3>2)
INSERT INTO product VALUES ('尺子', 12.345);
-- 错误:小数位数3 > 2
-- 同时违反两项规则
INSERT INTO product VALUES ('文具盒', 123.45);
-- 错误:总位数5>4 且 小数位2>2?(实际D=2允许2位小数,但总位数超限)
4. 查询验证
SELECT * FROM product;
执行结果应显示:
+-----------+-------+
| name | price |
+-----------+-------+
| 铅笔 | 12.34 |
| 橡皮 | 8.50 | -- 自动补零显示
| 笔记本 | 99.99 |
+-----------+-------+
重要注意事项
-
精度陷阱:
float
存储的是近似值,对精度要求高的场景(如金融计算)应使用decimal
类型-- 精度问题示例 INSERT INTO product VALUES ('计算器', 1.0 / 3.0); -- 存储为0.3333333432674408
-
参数可选性:可以不指定
(M,D)
,此时使用系统默认精度CREATE TABLE temp (value FLOAT); -- 不指定参数
-
显示补充:当实际小数位不足时,查询结果会自动补零显示(如
8.5
显示为8.50
)
通过以上实例,各位读者可以清晰看到:float(4,2)
可以存储 12.34
(刚好满位)、8.5
(位数不足)和 99.99
(边界值),但拒绝 100.00
(总位数超限)和 12.345
(小数位超限)。这种灵活的位数控制使 float
成为处理科学计算和大范围数值的理想选择,但切记它的近似特性可能带来精度问题!
2.decimal
在金融计算、货币交易等需要绝对精度的场景中,decimal
类型是 MySQL 中最值得信赖的数据类型。与 float
的近似存储不同,decimal
以固定精度存储数值,确保计算结果完全精确,避免浮点数常见的舍入误差问题。
核心特性解析
-
精确存储机制:
-
将数值拆分为整数部分和小数部分分别存储
-
采用定点数表示法,而非浮点数的科学计数法
-
完全避免二进制浮点数的精度损失问题
-
-
参数定义语法:
decimal(M, D)
-
M
(总精度):总位数(整数部分+小数部分),范围 1-65 -
D
(小数位数):小数点后的位数,范围 0-30 且 D ≤ M -
示例:
decimal(5,2)
可存储123.45
(5位总数,2位小数)
-
-
存储空间优化:
-
每9位数字占用4字节
-
存储空间 = 整数部分空间 + 小数部分空间
-
示例:
decimal(18,9)
需要 9字节(每部分9位,各需4字节,共8字节?实际需要9字节)
-
金融级精度演示
创建账户表
CREATE TABLE bank_account (account_id INT PRIMARY KEY,owner_name VARCHAR(50),-- 总位数10位,其中2位小数(最大存储:99,999,999.99)balance DECIMAL(10,2)
);
精确交易操作
-- 初始存款:精确存储
INSERT INTO bank_account VALUES (1001, '张三', 10000.00);
-- 存款利息计算(年化3.5%,按日计息)
UPDATE bank_account
SET balance = balance * (1 + 0.035/365)
WHERE account_id = 1001;
-- 查询结果(显示精确计算结果)
SELECT * FROM bank_account;
输出结果:
+------------+------------+--------------+
| account_id | owner_name | balance |
+------------+------------+--------------+
| 1001 | 张三 | 10000.958904 | -- 精确到小数点后6位
+------------+------------+--------------+
边界值测试
-- 最大允许值(符合decimal(10,2))
INSERT INTO bank_account VALUES (1002, '李四', 99999999.99); -- 成功
-- 超出整数部分限制
INSERT INTO bank_account VALUES (1003, '王五', 100000000.00);
-- 错误:总位数超过10位(整数部分8位+小数2位=10位,100000000是9位整数)
-- 超出小数部分限制
UPDATE bank_account SET balance = 12345.678 WHERE account_id = 1001;
-- 错误:小数位3位 > 2位(自动四舍五入为12345.68)
decimal vs float 关键对比
特性 | decimal | float |
---|---|---|
精度保证 | 精确存储(无误差) | 近似存储(有误差) |
适用场景 | 财务计算、货币金额 | 科学测量、大范围值 |
计算速度 | 较慢(精确计算开销大) | 较快 |
存储空间 | 较大(每9位需4字节) | 固定4字节 |
数值范围 | 受M限制(最大10^65) | 极大(约±10^38) |
小数处理 | 精确舍入 | 二进制近似 |
重要注意事项
-
四舍五入规则:
-- 显示指定精度时的自动舍入 INSERT INTO bank_account VALUES (1004, '赵六', 123.456); -- 实际存储:123.46(小数部分自动四舍五入到2位)
-
默认精度设置:
-- 不指定参数时使用默认精度 CREATE TABLE tax_records (amount DECIMAL -- 等效于decimal(10,0) );
-
零值处理:
-- 小数位不足时自动补零 INSERT INTO bank_account VALUES (1005, '钱七', 500.5); SELECT balance FROM bank_account WHERE account_id = 1005; -- 显示:500.50
-
计算精度扩展:
-- 计算过程中会保留最大精度 SELECT balance * 1.123456789 FROM bank_account; -- 结果将包含更多小数位
最佳实践建议
-
财务系统必选:所有货币金额、税率计算必须使用
decimal
-
合理设置精度:
-
货币:
decimal(19,4)
(兼容国际标准) -
百分比:
decimal(5,2)
(存储0.00~999.99%) -
科学测量:根据仪器精度确定
-
-
警惕隐式转换:
-- 混合类型计算可能导致精度丢失 SELECT balance + 123.456 FROM bank_account; -- 结果会被截断
-
性能权衡:高并发系统需评估精确计算带来的性能开销
黄金法则:当需要精确计算时选择
decimal
,当可接受近似值时选择float
。在金融、电商、账务系统中,decimal
的精度保障远重于其性能开销。
通过 decimal
类型,MySQL 为开发者提供了符合银行级标准的数值存储方案。它的精确性特性使其成为处理货币金额、财务计算和任何需要完美精度的商业场景的首选工具。
以上就是我想要讲述的MySQL中关于数值类型的定义,各位目前想要掌握它们,我的建议是在后续我进行DML的时候,跟着我一起敲代码。那么就可以更快的去掌握这些知识,毕竟比起死记硬背,动用往往是记忆最好的方式,下面我要进行字符串类型的讲述了。
3.字符串类型
3.1.char类型
1.语法
char类型相比数值类型,用法就比较简单了,下面先来看看它的语法。
char(L): 固定长度字符串,L是可以存储的长度,单位为字符,最大长度值可以为255
这个语法接受起来就比上面的float要简单很多,我们仅需知道,此时char括号里面的数字代表的事可以存储的字符的长度,记住,说的是字符的长度,而不是字节的长度,就比如,'你好'就代表两个字符,'A'代表一个字符等等,下面我就通过一个例子来告诉各位它的用法。
2.用法
下面,我继续从student表里面添加一列,充当家庭住址(place),其用法如下(此时设计表的增的操作,我上篇文章已经介绍了,忘记的读者自行去看我上篇文章)。
alter table student add place char(20);
此时,即可看到表里新增的一列。
下面我往里面插入20个字符(测试阈值),可以看到插入是成功的。
但是当我插入21个字符的时候,系统就会报错了,这就可以看出MySQL对于数据范围控制的严谨性。
3.2.varchar类型
1.语法
varchar(L): 可变长度字符串,L表示字符长度,最大长度65535个字节
varchar
也是一种字符串类型。你可能会问,既然已有 char
类型,为何还需要 varchar
?关键在于它们的存储机制不同。
如前所述,char
是固定长度的字符串。例如,当你定义一个长度为 20 个字符的 char
字段时,即使你只插入了一个字符的数据,数据库依然会分配完整的 20 个字符空间。
而 varchar
则是可变长度的字符串。在同样的场景下(定义长度为 20,但仅插入 1 个字符),varchar
类型只会分配实际所需的空间,即仅占用 1 个字符的空间。
2.用法
因为它和char类型的字符串其实很像(只不过是一个静态一个动态),所以此时我就不写用法了(偷懒一下)。
3.3.char类型和varchar类型的比较
1.比较
此时,我们可以通过一张表格来看出这两个类型的区别。
从这张图可以看出这俩的区别,我刚才也说了,varchar是变长的字符串,所以它的大小是根据当时字符大小来决定的,而char类型是定长字符串,无论输入了多少个字符,只要在和合理的范围内,它们的大小是确定的。
2.如何选择这两种类型
-
如果数据确定长度都一样,就使用定长(char),比如:身份证,手机号,md5 【但是我一般也是用varchar】。
-
如果数据长度有变化,就使用变长(varchar), 比如:名字,地址,但是你要保证最长的能存的进去 。
-
定长的磁盘空间比较浪费,但是效率高。
-
变长的磁盘空间比较节省,但是效率低。
-
定长的意义是,直接开辟好对应的空间
-
变长的意义是,在不超过自定义范围的情况下,用多少,开辟多少。
4.日期和时间类型
1.相关函数
常用的日期有如下三个:
-
date:日期。‘yyyy-mm-dd’,占用三个字节。
-
datetime:时间日期格式,‘yyyy-mm-dd HH:ii:ss’表示范围从1000到9999,占用八个字节。
-
timestamp:时间戳(比较常见的概念,之前我在C语言也使用过它),从1970年开始的yyyy-mm-dd HH:ii:ss格式和datetime完全一致,占用四个字节。
2.使用方法
1.date函数
我们先来简单的使用一下date函数,此时我们往student表里新插入一列,bir代表学生的出生日期。
alter table student add bir date;
往里面插入一个元素,这里我就拿我自己的出生日期作为要插入的元素,因为这里面设计到了DML的知识,所以各位先不用记住它的用法。
insert into student(bir) values('2005-2-17');
检查一下此时是否插入成功。
2.datetime
下面我们继续插入新的一列,此时就用enr来表示,代表着入学的年份。
alter table student add enr datetime;
往里面插入随机一个元素,记住用年月日时分秒来表示。
insert into student(enr) values('2023-9-3-12:32:12');
此时就代表插入成功,看一下student里面存放的元素。
3.timestamp
由于其用法和datetime类似,这里我就不多介绍了(后续我可能重新补充一下)。
5.小结
此时文章到这里就结束了,这篇文章写的比较赶,但也不能说是很赶,因为我前后大约四天才写完的,所以文章可能读起来不是那么流畅,这里我先说一声抱歉了,出现这样的原因是因为我这周是期末周,大多时间都是在‘预习’知识,信号和系统真的很痛苦,我是真的不太喜欢这门课,导致我学起来特别的难受,到现在我的脑子还是比较混乱的。本文其实还有集合类型没有讲述,但是由于我很少使用它,所以我就先不写了,后期我可能会补充一点。在最后的hike,祝各位同时处在期末周的大学生们取得一个好成绩,祝各位已经放假的大学生们暑假快乐,祝所有人身体健康,每天都快快乐乐的,我是忘梓,一个默默无闻的小博主,各位大佬们,我们下篇文章见啦!