概述

常见数据类型的属性

整数类型

sql
CREATE TABLE test_int1(
f1 TINYINT,
f2 SMALLINT,
f3 MEDIUMINT,
f4 INTEGER,
f5 BIGINT
);
可选属性
①显示宽度:可以为每一个字段设置宽度[位数],但不具备强制力[取决于字段类型本身]
sql
CREATE TABLE test_int2(
f1 INT,
f2 INT(5),
f3 INT(5) ZEROFILL
#① 显示宽度为5。当insert的值不足5位时,使用0填充。
#②当使用ZEROFILL时,自动会添加UNSIGNED
)
INSERT INTO test_int2(f1,f2)
VALUES(123,123),(123456,123456);
SELECT * FROM test_int2;
INSERT INTO test_int2(f3)
VALUES(123),(123456);
②UNSIGNED:无符号类型(非负),所有的整数类型都有一个可选的属性UNSIGNED(无符号属性),无符号整数类型的最小取值为0[增加一个宽度]
sql
CREATE TABLE test_int3(
f1 INT UNSIGNED
);
DESC test_int3;
INSERT INTO test_int3
VALUES(2412321);
#Out of range value for column 'f1' at row 1
INSERT INTO test_int3
VALUES(4294967296);
③ZEROFILL : 0填充,结合宽度可以调整展示样式
适用场景
TINYINT :一般用于枚举数据,比如系统设定取值范围很小且固定的场景。
SMALLINT :可以用于较小范围的统计数据,比如统计工厂的固定资产库存数量等。
MEDIUMINT :用于较大整数的计算,比如车站每日的客流量等。
INT、INTEGER :取值范围足够大,一般情况下不用考虑超限问题,用得最多。比如商品编号。
BIGINT :只有当你处理特别巨大的整数时才会用到。比如双十一的交易量、大型门户网站点击量、证 券公司衍生产品持仓等。
要考虑存储空间和可靠性的平衡问题
浮点类型

MySQL 存储浮点数的格式为: 符号(S) 、 尾数(M) 和 阶码(E) 。
MySQL支持非标准语法:FLOAT(M,D) 或 DOUBLE(M,D) 。这里,M称为 精度 ,D称为 标度 。(M,D)中 M=整数位+小数 位,D=小数位。 D<=M<=255,0<=D<=30。
sql
CREATE TABLE test_double1(
f1 FLOAT,
f2 FLOAT(5,2),
f3 DOUBLE,
f4 DOUBLE(5,2)
);
DESC test_double1;
INSERT INTO test_double1(f1,f2)
VALUES(123.45,123.45);
SELECT * FROM test_double1;
INSERT INTO test_double1(f3,f4)
VALUES(123.45,123.456); #存在四舍五入
#Out of range value for column 'f4' at row 1
INSERT INTO test_double1(f3,f4)
VALUES(123.45,1234.456);
#Out of range value for column 'f4' at row 1
INSERT INTO test_double1(f3,f4)
VALUES(123.45,999.995);
精度问题
sql
CREATE TABLE test_double2(
f1 DOUBLE
);
INSERT INTO test_double2
VALUES(0.47),(0.44),(0.19);
SELECT SUM(f1)
FROM test_double2;
SELECT SUM(f1) = 1.1,1.1 = 1.1
FROM test_double2;
因为浮点数是不准确的,所以我们要避免使用"="来判断两个数是否相等
定点数的类型

用 DECIMAL(M,D) 的方式表示高精度小数。其中,M被称为精度,D被称为标度。0<=M<=65,0<=D<=30,D<M。例如,定义DECIMAL(5,2)的类型,表示该列取值范围是-999.99~999.99。
定点数在MySQL内部是以字符串的形式进行存储,这就决定了它一定是精准的。
sql
CREATE TABLE test_decimal1(
f1 DECIMAL,
f2 DECIMAL(5,2)
);
DESC test_decimal1;
INSERT INTO test_decimal1(f1)
VALUES(123),(123.45);
SELECT * FROM test_decimal1;
INSERT INTO test_decimal1(f2)
VALUES(999.99);
INSERT INTO test_decimal1(f2)
VALUES(67.567);#存在四舍五入
#Out of range value for column 'f2' at row 1
INSERT INTO test_decimal1(f2)
VALUES(1267.567);
#Out of range value for column 'f2' at row 1
INSERT INTO test_decimal1(f2)
VALUES(999.995);
开发经验
由于 DECIMAL 数据类型的精准性,在开发中,除了极少数(比如商品编号)用到整数类型
外,其他的数值都用的是 DECIMAL
位类型

sql
CREATE TABLE test_bit1(
f1 BIT,
f2 BIT(5),
f3 BIT(64)
);
DESC test_bit1;
INSERT INTO test_bit1(f1)
VALUES(0),(1);
SELECT *
FROM test_bit1;
#Data too long for column 'f1' at row 1
INSERT INTO test_bit1(f1)
VALUES(2);
INSERT INTO test_bit1(f2)
VALUES(31);
#Data too long for column 'f2' at row 1
INSERT INTO test_bit1(f2)
VALUES(32);
SELECT BIN(f1),BIN(f2),HEX(f1),HEX(f2)
FROM test_bit1;
#此时+0以后,可以以十进制的方式显示数据
SELECT f1 + 0, f2 + 0
FROM test_bit1;
注:使用SELECT命令查询位字段时,可以用BIN()[二进制]或HEX()[十六进制]函数进行读取。
日期与时间类型

YEAR类型
只需要1个字节的存储空间
以4位字符串或数字格式表示YEAR类型,其格式为YYYY,最小值为1901,最大值为2155。
以2位字符串格式表示YEAR类型,最小值为00,最大值为99。
当取值为01到69时,表示2001到2069;
当取值为70到99时,表示1970到1999;
当取值整数的0或00添加的话,那么是0000年;
当取值是日期/字符串的'0'添加的话,是2000年。
sql
CREATE TABLE test_year(
f1 YEAR,
f2 YEAR(4)
);
DESC test_year;
INSERT INTO test_year(f1)
VALUES('2021'),(2022);
SELECT * FROM test_year;
INSERT INTO test_year(f1)
VALUES ('2155');
#Out of range value for column 'f1' at row 1
INSERT INTO test_year(f1)
VALUES ('2156');
INSERT INTO test_year(f1)
VALUES ('69'),('70');
INSERT INTO test_year(f1)
VALUES (0),('00');
DATE类型
只需要3个字节的存储空间
以 YYYY-MM-DD 格式或者 YYYYMMDD 格式表示的字符串日期,
其最小取值为1000-01-01,最大取值为9999-12-03
sql
CREATE TABLE test_date1(
f1 DATE
);
DESC test_date1;
INSERT INTO test_date1
VALUES ('2020-10-01'), ('20201001'),(20201001);
INSERT INTO test_date1
VALUES ('00-01-01'), ('000101'), ('69-10-01'), ('691001'), ('70-01-01'), ('700101'), ('99-01-01'), ('990101');
INSERT INTO test_date1
VALUES (000301), (690301), (700301), (990301); #存在隐式转换
INSERT INTO test_date1
VALUES (CURDATE()),(CURRENT_DATE()),(NOW());
SELECT *
FROM test_date1;
TIME类型
只需要3个字节的存储空间,不包含日期
使用"HH:MM:SS"格式来表示TIME类型,其中,HH表示小时,MM表示分钟,SS表示秒
可以使用带有冒号的 字符串,比如' 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
sql
CREATE TABLE test_time1(
f1 TIME
);
DESC test_time1;
INSERT INTO test_time1
VALUES('2 12:30:29'), ('12:35:29'), ('12:40'), ('2 12:40'),('1 05'), ('45');
INSERT INTO test_time1
VALUES ('123520'), (124011),(1210);
INSERT INTO test_time1
VALUES (NOW()), (CURRENT_TIME()),(CURTIME());
SELECT *
FROM test_time1;
DATETIME类型
需要8个字节的存储空间
表示为 YYYY-MM-DD HH:MM:SS / YY-MM-DD HH:MM:SS ,其中YYYY/YY表示年份,MM表示月 份,DD表示日期,HH表示小时,MM表示分钟,SS表示秒
sql
CREATE TABLE test_datetime1(
dt DATETIME
);
INSERT INTO test_datetime1
VALUES ('2021-01-01 06:50:30'), ('20210101065030');
INSERT INTO test_datetime1
VALUES ('99-01-01 00:00:00'), ('990101000000'), ('20-01-01 00:00:00'), ('200101000000');
INSERT INTO test_datetime1
VALUES (20200101000000), (200101000000), (19990101000000), (990101000000);
INSERT INTO test_datetime1
VALUES (CURRENT_TIMESTAMP()), (NOW()),(SYSDATE());
SELECT *
FROM test_datetime1;
TIMESTAMP类型
需要4个字节的存储空间
表示为 YYYY-MM-DD HH:MM:SS ,只能存储 "1970-01-01 00:00:01 UTC"到"2038-01-19 03:14:07 UTC"之间的时间。其中,UTC表示世界统一时间,也叫 作世界标准时间
sql
CREATE TABLE test_timestamp1(
ts TIMESTAMP
);
INSERT INTO test_timestamp1
VALUES ('1999-01-01 03:04:50'), ('19990101030405'), ('99-01-01 03:04:05'), ('990101030405');
INSERT INTO test_timestamp1
VALUES ('2020@01@01@00@00@00'), ('20@01@01@00@00@00');
INSERT INTO test_timestamp1
VALUES (CURRENT_TIMESTAMP()), (NOW());
#Incorrect datetime value
INSERT INTO test_timestamp1
VALUES ('2038-01-20 03:14:07');
SELECT *
FROM test_timestamp1;
对比DATETIME 和 TIMESTAMP
sql
CREATE TABLE temp_time(
d1 DATETIME,
d2 TIMESTAMP
);
INSERT INTO temp_time VALUES('2021-9-2 14:45:52','2021-9-2 14:45:52');
INSERT INTO temp_time VALUES(NOW(),NOW());
SELECT * FROM temp_time;
#修改当前的时区
SET time_zone = '+9:00';
SELECT * FROM temp_time;
两个日期比较大小或日期计算时,TIMESTAMP更方便、更快[存放的是毫秒数]。
TIMESTAMP和时区有关。TIMESTAMP会根据用户的时区不同,显示不同的结果。而DATETIME则只能 反映出插入时当地的时区,其他时区的人查看数据必然会有误差的。
开发经验
用得最多的日期时间类型,就是 DATETIME 。
一般存注册时间、商品发布时间等,不建议使用DATETIME存储,而是使用 时间戳 ,因为 DATETIME虽然直观,但不便于计算
文本字符串类型

CHAR与VARCHAR类型

CHAR类型
如果保存时,数据的实际长度比CHAR类型声明的长度小,则会在 右侧填充空格以达到指定的长 度。当MySQL检索CHAR类型的数据时,CHAR类型的字段会去除尾部的空格。
sql
CREATE TABLE test_char1(
c1 CHAR,
c2 CHAR(5)
);
INSERT INTO test_char1(c1)
VALUES('a');
#Data too long for column 'c1' at row 1
INSERT INTO test_char1(c1)
VALUES('ab');#默认情况下是一个字符
INSERT INTO test_char1(c2)
VALUES('ab');
INSERT INTO test_char1(c2)
VALUES('hello');
INSERT INTO test_char1(c2)
VALUES('尚');
INSERT INTO test_char1(c2)
VALUES('硅谷');
INSERT INTO test_char1(c2)
VALUES('尚硅谷教育');
#Data too long for column 'c2' at row 1
INSERT INTO test_char1(c2)
VALUES('尚硅谷IT教育');
SELECT * FROM test_char1;
SELECT CONCAT(c2,'***')
FROM test_char1;
INSERT INTO test_char1(c2)
VALUES('ab ');
SELECT CHAR_LENGTH(c2)
FROM test_char1;
VARCHAR类型
VARCHAR(M) 定义时, 必须指定长度M
varchar(20):指的是20字符
检索VARCHAR类型的字段数据时,会保留数据尾部的空格。VARCHAR类型的字段所占用的存储空间为字符串实际长度加1个字节[记录长度]。
sql
CREATE TABLE test_varchar1(
NAME VARCHAR #错误,必须指定字符个数
);
#Column length too big for column 'name' (max = 21845); use BLOB or TEXT instead
CREATE TABLE test_varchar2(
NAME VARCHAR(65535)#使用utf8字符集,每一个字符占3个字节
);
sql
CREATE TABLE test_varchar3(
NAME VARCHAR(5)
);
INSERT INTO test_varchar3
VALUES('尚硅谷'),('尚硅谷教育');
#Data too long for column 'NAME' at row 1
INSERT INTO test_varchar3
VALUES('尚硅谷IT教育');

存储很短的信息[VARCHAR需要额外字节保留长度]
固定长度的信息[VARCHAR的动态性需求消失]
十分频繁改变的字段[VARCHAR需要额外时间运算,消耗增加]
-->CHAR
不同存储引擎下:
MyISAM:推荐使用CHAR,整个表静态化,检索效率更高
MEMORY:均可,在处理时均作为CHAR类型处理
InnoDB:推荐使用VARCHAR,内部的行存储格式并没有区分固定长度和可变长度列,而且主要影响性能的因素是数据行使用的存储总量
TEXT类型

其实际存储长度不确定,在MySQL中不允许作为主键
sql
CREATE TABLE test_text(
tx TEXT
);
INSERT INTO test_text
VALUES('atguigu ');
SELECT CHAR_LENGTH(tx)
FROM test_text; #10
ENUM类型
只允许从成员中选取单个值,不能一次选取多个值

sql
CREATE TABLE test_text(
tx TEXT
);
INSERT INTO test_text
VALUES('atguigu ');
SELECT CHAR_LENGTH(tx)
FROM test_text; #10
#8. ENUM类型
CREATE TABLE test_enum(
season ENUM('春','夏','秋','冬','unknow')
);
INSERT INTO test_enum
VALUES('春'),('秋');
SELECT * FROM test_enum;
#Data truncated for column 'season' at row 1
INSERT INTO test_enum
VALUES('春,秋');
#Data truncated for column 'season' at row 1
INSERT INTO test_enum
VALUES('人');
INSERT INTO test_enum
VALUES('unknow');
#忽略大小写的
INSERT INTO test_enum
VALUES('UNKNOW');
#可以使用索引进行枚举元素的调用
INSERT INTO test_enum
VALUES(1),('3');
# 没有限制非空的情况下,可以添加null值
INSERT INTO test_enum
VALUES (NULL);
SET类型
SET表示一个字符串对象,可以包含0个或多个成员,但成员个数的上限为64。设置字段值时,可以取取值范围内的 0 个或多个值

sql
CREATE TABLE test_set(
s SET ('A', 'B', 'C')
);
INSERT INTO test_set (s) VALUES ('A'), ('A,B');
#插入重复的SET类型成员时,MySQL会自动删除重复的成员
INSERT INTO test_set (s) VALUES ('A,B,C,A');
#向SET类型的字段插入SET成员中不存在的值时,MySQL会抛出错误。
INSERT INTO test_set (s) VALUES ('A,B,C,D');
SELECT *
FROM test_set;
二进制字符串类型
存储一些二进制数据,比如可以存储图片、音频和视频等二进制数据
BINARY与VARBINARY类型
BINARY和VARBINARY类似于CHAR和VARCHAR,只是它们存储的是二进制字符串。

sql
CREATE TABLE test_binary1(
f1 BINARY,
f2 BINARY(3),
#f3 VARBINARY,
f4 VARBINARY(10)
);
DESC test_binary1;
INSERT INTO test_binary1(f1,f2)
VALUES('a','abc');
SELECT * FROM test_binary1;
#Data too long for column 'f1' at row 1
INSERT INTO test_binary1(f1)
VALUES('ab');
INSERT INTO test_binary1(f2,f4)
VALUES('ab','ab');
SELECT LENGTH(f2),LENGTH(f4)
FROM test_binary1;
BLOB类型
BLOB是一个 二进制大对象 ,可以容纳可变数量的数据。可以存储一个二进制的大对象,比如 图片 、 音频 和 视频 等。

sql
CREATE TABLE test_blob1(
id INT,
img MEDIUMBLOB
);
INSERT INTO test_blob1(id)
VALUES (1001);
SELECT *
FROM test_blob1;
JSON类型
JSON(JavaScript Object Notation)是一种轻量级的 数据交换格式 。
JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式。
sql
CREATE TABLE test_json(
js json
);
INSERT INTO test_json (js)
VALUES ('{"name":"songhk", "age":18, "address":{"province":"beijing", "city":"beijing"}}');
SELECT * FROM test_json;
SELECT js -> '$.name' AS NAME,js -> '$.age' AS age ,js -> '$.address.province' AS province, js -> '$.address.city' AS city
FROM test_json;
开发选择
在定义数据类型时,如果确定是整数,就用 INT;
如果是小数,一定用定点数类型DECIMAL(M,D) ;
必须使用,超过议将数据拆成整数和小数并分开存储
如果是日期与时间,就用DATETIME;
字符串长度几乎相等,使用 CHAR 定长字符串类型;
VARCHAR 是可变长字符串,不预先分配存储空间,长度不要超过 5000。存储长度大于此值,定义字段类型为 TEXT,独立出来一张表,用主键来对应,避免影响其它字段索引效率。