SQL数据类型

概述

常见数据类型的属性

整数类型

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,独立出来一张表,用主键来对应,避免影响其它字段索引效率。

相关推荐
m0_624578592 小时前
CSS定位如何实现多行文字垂直居中_通过绝对定位模拟表格
jvm·数据库·python
Nyarlathotep01132 小时前
并发集合类(3):LinkedBlockingQueue
java·后端
李温候2 小时前
互联网大厂Java求职者面试全攻略
java·数据库·面试·orm·构建工具·web框架·互联网大厂
摇滚侠3 小时前
软件开发外包项目组,如何提高代码质量和开发效率
java·开发语言·前端·ide·intellij-idea
dfdfadffa3 小时前
mysql如何排查网络延迟引起的数据库连接问题_使用ping测试
jvm·数据库·python
2303_821287383 小时前
JavaScript中Redux-Thunk处理异步Action的任务流
jvm·数据库·python
bzmK1DTbd3 小时前
MongoDB聚合框架:Java驱动下的数据聚合操作
java·python·mongodb
IT空门:门主3 小时前
spring ai alibaba -流式+invoke的人工介入的实现
java·后端·spring