【MySQL】第八章 数据类型

1,整形

对于整形类型的使用 如果设置了显示宽度,那么插入的数据宽度超过显示宽度限制,会不会截断或插入失败?例如:INT(5) 答案:不会对插入的数据有任何影响,还是按照类型的实际宽度进行保存,即 显示宽度与类型可以存储的值范围无关 。从MySQL 8.0.17开始,整数数据类型不推荐使用显示宽度属性

那么这个显示宽度的存在还有什么意义呢?

是用来配合ZEROFILL 一起使用的。 原来,在 int(M) 中,M 的值跟 int(M) 所占多少存储空间并无任何关系。 int(3)、int(4)、int(8) 在磁盘上都是占用 4 bytes 的存储空间。也就是说,int(M),必须和UNSIGNED ZEROFILL一起使用才有意义。如果整数值超过M位,就按照实际位数存储。只是无须再用字符 0 进行填充。

sql 复制代码
# 创建整形数据
CREATE TABLE test1(
    f1 TINYINT,
    f2 SMALLINT,
    f3 MEDIUMINT
    f4 INT,
    f5 BIGINT,
);
​
# 常见报错 (超出范围报错)
# Out of range value for column 'f1' at row 1
INSERT INTO test_int1(f1)
VALUES(128);
​
# ZEROFILL的用法
CREATE TABLE test_int2(
f1 INT,
f2 INT(5),
f3 INT(5) ZEROFILL  #① 显示宽度为5。当insert的值不足5位时,使用0填充。 ②当使用ZEROFILL时,自动会添加UNSIGNED
)

在评估用哪种整数类型的时候,你需要考虑存储空间可靠性的平衡问题:一方 面,用占用字节数少的整数类型可以节省存储空间;另一方面,要是为了节省存储空间, 使用的整数类型取值范围太小,一旦遇到超出取值范围的情况,就可能引起 系统错误 ,影响可靠性

2,浮点类型

为什么浮点数类型的无符号数取值范围,只相当于有符号数取值范围的一半,也就是只相当于有符号数取值范围大于等于零的部分呢?

MySQL 存储浮点数的格式为: 符号(S) 、 尾数(M) 和 阶码(E) 。因此,无论有没有符号,MySQL 的浮点数都会存储表示符号的部分。因此, 所谓的无符号数取值范围,其实就是有符号数取值范围大于等于零的部分

所以我们并不用去考虑有符号和无符号类型,因为占用的空间都是一样的,符号的存储方式与证书的存储方式不太一样

MySQL允许使用 非标准语法 (其他数据库未必支持,因此如果涉及到数据迁移,则最好不要这么用): FLOAT(M,D) 或 DOUBLE(M,D) 。这里,M称为 精度 ,D称为 标度 。(M,D)中 M=整数位+小数位,D=小数位。 D<=M<=255,0<=D<=30

如果存储时,小数点部分若超出范围,就分以下情况:

(1)若四舍五入 后,整数部分没有超出范围,则只警告,但能成功操作并四舍五入删除多余的小数位后保存。例如在FLOAT(5,2)列内插入999.009,近似结果是999.01。

(2)若四舍五入 后,整数部分超出范围,则MySQL报错,并拒绝处理。如FLOAT(5,2)列内插入999.995和-999.995都会报错。

MySQL 8.0.17 开始,FLOAT(M,D) 和**DOUBLE(M,D)**用法在官方文档中已经明确不推荐使用,将来可能被移除。另外,关于浮点型FLOAT和DOUBLE的UNSIGNED也不推荐使用了,将来也可能被移除

在编程中,如果用到浮点数,要特别注意误差问题,因为浮点数是不准确的,所以我们要避免使用"="来判断两个数是否相等,同时,在一些对精确度要求较高的项目中,千万不要使用浮点数,不然会导致结果错误,甚至是造成不可挽回的损失。那么,MySQL 有没有精准的数据类型呢?当然有,这就是定点数类型: DECIMAL

sql 复制代码
CREATE TABLE test_double2(
f1 DOUBLE
);
INSERT INTO test_double2
VALUES(0.47),(0.44),(0.19);
​
​
mysql> SELECT SUM(f1)
-> FROM test_double2;
+--------------------+
| SUM(f1) |
+--------------------+
| 1.0999999999999999 |
+--------------------+
1 row in set (0.00 sec)
​
​
mysql> SELECT SUM(f1) = 1.1,1.1 = 1.1
-> FROM test_double2;
+---------------+-----------+
| SUM(f1) = 1.1 | 1.1 = 1.1 |
+---------------+-----------+
| 0 | 1 |
+---------------+-----------+
1 row in set (0.00 sec)
​
# 如果将上面的类型改为FLOAT类型,现实的数字是1.0999999940395355
3,定点数

使用 DECIMAL(M,D) 的方式表示高精度小数。其中,M被称为精度,D被称为标度。0<=M<=65,0<=D<=30,D<M。例如,定义DECIMAL(5,2)的类型,表示该列取值范围是-999.99~999.99。DECIMAL(M,D) 的最大取值范围与DOUBLE类型一样,但是有效的数据范围是由M和D决定的

DECIMAL 的存储空间并不是固定的,总字节数 = 整数部分存储字节 + 小数部分存储字节 + 符号位(1字节) ,在一些对精度要求不高的场景下,比起占用同样字节长度的定点数,浮点数表达的数值范围可以更大一些,DECIMAL 是十进制定点存储 ,每字节仅能表示少量十进制数字(比如 4 字节最多存 9 位十进制数);而浮点数(如 4 字节 FLOAT)是二进制浮点存储 ,DECIMAL 的十进制存储逻辑是:直接按「十进制数字位」存储(比如 0.1 存储为 "1×10⁻¹",而非二进制循环数),从根源上避免了进制转换的精度丢失。

4,位类型

BIT类型,如果没有指定(M),默认是1位,表示只能存储1位的二进制,这里(M)表示的是二进制的位数,最小值为1,最大值为64

sql 复制代码
CREATE TABLE test_bit1(
f1 BIT,
f2 BIT(5),
f3 BIT(64)
);
INSERT INTO test_bit1(f1)
VALUES(1);
#Data too long for column 'f1' at row 1
INSERT INTO test_bit1(f1)
VALUES(2);
INSERT INTO test_bit1(f2)
VALUES(23);
​
​
mysql> SELECT * FROM test_bit1;
+------------+------------+------------+
| f1 | f2 | f3 |
+------------+------------+------------+
| 0x01 | NULL | NULL |
| NULL | 0x17 | NULL |
+------------+------------+------------+
2 rows in set (0.00 sec)
​
​
mysql> SELECT BIN(f2),HEX(f2)
-> FROM test_bit1;
+---------+---------+
| BIN(f2) | HEX(f2) |
+---------+---------+
| NULL | NULL |
| 10111 | 17 |
+---------+---------+
2 rows in set (0.00 sec)
​
# 使用b+0查询数据的时候,可以直接查询出存储的十进制数据的值
mysql> SELECT f2 + 0
-> FROM test_bit1;
+--------+
| f2 + 0 |
+--------+
| NULL |
| 23 |
+--------+
2 rows in set (0.00 sec)
5,日期与时间类型

1,YEAR

1字节存储空间

以4位字符串或数字格式表示YEAR类型,其格式为YYYY,最小值为1901,最大值为2155

以2位字符串格式表示YEAR类型,最小值为00,最大值为99。 当取值为01到69时,表示2001到2069; 当取值为70到99时,表示1970到1999; 当取值整数的0或00添加的话,那么是0000年; 当取值是日期/字符串的'0'添加的话,是2000年

2位字符串格式表示YEAR的话,这个从MySQL5.5.27开始,2位格式的YEAR已经不推荐使用

2,TIME

3字节存储空间

在MySQL中,向TIME类型的字段插入数据时,也可以使用几种不同的格式。 (1)可以使用带有冒号的 字符串,比如**' D HH:MM:SS' 、' HH:MM:SS '**、' HH:MM '、' D HH:MM '、' D HH '或' SS '格式,都能被正

确地插入TIME类型的字段中。其中D表示天,其最小值为0,最大值为34。如果使用带有D格式的字符串

插入TIME类型的字段时,D会被转化为小时计算格式为D*24+HH。当使用带有冒号并且不带D的字符串

表示时间时,表示当天的时间,比如12:10表示12:10:00,而不是00:12:10。

(2)可以使用不带有冒号的 字符串或者数字,格式为' HHMMSS '或者 HHMMSS 。如果插入一个不合法的字符串或者数字,MySQL在存储数据时,会将其自动转化为00:00:00进行存储。比如1210,MySQL会将最右边的两位解析成秒,表示00:12:10,而不是12:10:00。

(3)使用 CURRENT_TIME() 或者 NOW() ,会插入当前系统的时间。

3,DATE

3字节存储空间

以 YYYY-MM-DD 格式或者 YYYYMMDD 格式表示的字符串日期,其最小取值为1000-01-01,最大取值为9999-12-03。YYYYMMDD格式会被转化为YYYY-MM-DD格式

以 YY-MM-DD 格式或者 YYMMDD 格式表示的字符串日期,此格式中,年份为两位数值或字符串满足YEAR类型的格式条件为:当年份取值为00到69时,会被转化为2000到2069;当年份取值为70到99时,会被转化为1970到1999。

使用 CURRENT_DATE() 或者 NOW() 函数,会插入当前系统的日期

4,DATETIME,TIMESTAMP

都是为可以表示为 YYYY-MM-DD HH:MM:SS ,其中YYYY表示年份,MM表示月份,DD表示日期,HH表示小时,MM表示分钟,SS表示秒。

存储数据的时候需要对当前时间所在的时区进行转换,查询数据的时候再将时间转换回当前的时

区。因此,使用TIMESTAMP存储的同一个时间值,在不同的时区查询时会显示不同的时间

6,文本字符串类型

1,CHAR,VARCHAR

1,CHAR(M) CHAR(M) 类型一般需要预先定义字符串长度。如果不指定(M),则表示长度默认是1个字符。 如果保存时,数据的实际长度比CHAR类型声明的长度小,则会在 右侧填充 空格以达到指定的长度。当MySQL检索CHAR类型的数据时,CHAR类型的字段会去除尾部的空格。 定义CHAR类型字段时,声明的字段长度即为CHAR类型字段所占的存储空间的字节数。

2,VARCHAR(M) VARCHAR(M) 定义时, 必须指定 长度M,否则报错。 MySQL4.0版本以下,varchar(20):指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节) ;MySQL5.0版本以上,varchar(20):指的是20字符。 检索VARCHAR类型的字段数据时,会保留数据尾部的空格。VARCHAR类型的字段所占用的存储空间为字符串实际长度加1个字节

情况1:存储很短的信息。比如门牌号码101,201......这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的,结果得不偿失

情况3:十分频繁改变的column。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char来说是不需要的

2,枚举ENUM和集合SET

1,ENUM

2,SET

相关推荐
小陈工39 分钟前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
0xDevNull5 小时前
MySQL数据冷热分离详解
后端·mysql
科技小花5 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸5 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain5 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希6 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神6 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员6 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java6 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿6 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb