【SQL】之数据类型

  • 数据类型
    • 整数类型
    • 浮点类型
    • 定点数类型
      • 浮点数 vs 定点数
    • 位类型
    • 日期与时间类型
      • TIMESTAMP和DATETIME的区别:
    • 文本字符串类型
      • 哪些情况使用 CHAR 或 VARCHAR 更好
    • enum类型
    • set类型
    • 二进制字符串类型
      • TEXT和BLOB的使用注意事项:
    • json类型
  • 选择建议
    • 字符串的选择:

数据类型

整数类型

TINYINT :一般用于枚举数据,比如系统设定取值范围很小且固定的场景。
SMALLINT :可以用于较小范围的统计数据,比如统计工厂的固定资产库存数量等。
MEDIUMINT :用于较大整数的计算,比如车站每日的客流量等。
INT、INTEGER :取值范围足够大,一般情况下不用考虑超限问题,用得最多。比如商品编号。
BIGINT :只有当你处理特别巨大的整数时才会用到。比如双十一的交易量、大型门户网站点击量、证
券公司衍生产品持仓等。

在实际工作中,系统故障产生的成本远远超过增加几个字段存储空间所产生的成本。因此,首先确保数据不会超过取值范围,再去考虑如何节省存储空间。

浮点类型

定点数类型

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 的存储空间并不是固定的,由精度值M决定,总共占用的存储空间为M+2个字节。也就是说,在一些对精度要求不高的场景下,比起占用同样字节长度的定点数,浮点数表达的数值范围可以更大一些。
  • 定点数在MySQL内部是以字符串的形式进行存储,这就决定了它一定是精准的。
  • 当DECIMAL类型不指定精度和标度时,其默认为DECIMAL(10,0)没有小数位。当数据的精度超出了定点数类型的精度范围时,则MySQL同样会进行四舍五入处理。

浮点数 vs 定点数

  • 浮点数相对于定点数的优点是在长度一定的情况下,浮点类型取值范围大,但是不精准,适用于需要取值范围大,又可以容忍微小误差的科学计算场景(比如计算化学、分子建模、流体动力学等)
  • 定点数类型取值范围相对小,但是精准,没有误差,适合于对精度要求极高的场景 (比如涉及金额计算的场景)

“由于 DECIMAL 数据类型的精准性,在我们的项目中,除了极少数(比如商品编号)用到整数类型外,其他的数值都用的是 DECIMAL,原因就是这个项目所处的零售行业,要求精准,一分钱也不能差。”

位类型

日期与时间类型

YEAR 类型通常用来表示年
DATE 类型通常用来表示年、月、日
TIME 类型通常用来表示时、分、秒
DATETIME 类型通常用来表示年、月、日、时、分、秒
TIMESTAMP 类型通常用来表示带时区的年、月、日、时、分、秒

  • TIMESTAMP存储数据的时候需要对当前时间所在的时区进行转换,查询数据的时候再将时间转换回当前的时区。因此,使用TIMESTAMP存储的同一个时间值,在不同的时区查询时会显示不同的时间。
  • TIMESTAMP存储的时间范围比DATETIME要小很多,只能存储“1970-01-01 00:00:01UTC”到“2038-01-19 03:14:07 UTC”之间的时间。其中,UTC表示世界统一时间,也叫作世界标准时间。
  • 如果向TIMESTAMP类型的字段插入的时间超出了TIMESTAMP类型的范围,则MySQL会抛出错误信息。

使用CURRENT_DATE() 或者NOW() 函数,会插入当前系统的日期。
使用函数CURRENT_TIMESTAMP() ,可以向DATETIME类型的字段插入系统的当前日期和时间。

-- 创建数据表,表中包含一个TIMESTAMP类型的字段ts。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());
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');

TIMESTAMP和DATETIME的区别:

  • TIMESTAMP存储空间比较小,表示的日期时间范围也比较小
  • 底层存储方式不同,TIMESTAMP底层存储的是毫秒值,距离1970-1-1 0:0:0 0毫秒的毫秒值。
  • 两个日期比较大小或日期计算时,TIMESTAMP更方便、更快
  • TIMESTAMP和时区有关。TIMESTAMP会根据用户的时区不同显示不同的结果。而DATETIME则只能反映出插入时当地的时区,其他时区的人查看数据必然会有误差的。

用得最多的日期时间类型是 DATETIME 。虽然 MySQL 也支持 YEAR(年)、 TIME(时间)、DATE(日期),以及 TIMESTAMP 类型,但是在实际项目中,尽量用 DATETIME 类型。因为这个数据类型包括了完整的日期和时间信息,取值范围也最大,使用起来比较方便。毕竟,如果日期时间信息分散在好几个字段,很不容易记,而且查询的时候,SQL 语句也会更加复杂。

此外,一般存注册时间、商品发布时间等,不建议使用DATETIME存储,而是使用时间戳,因为DATETIME虽然直观,但不便于计算。

mysql> SELECT UNIX_TIMESTAMP();
+------------------+
| UNIX_TIMESTAMP() |
+------------------+
| 1635932762 |
+------------------+

文本字符串类型

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

CREATE TABLE test_varchar1(
NAME VARCHAR #错误
);#Column length too big for column 'NAME' (max = 21845);
CREATE TABLE test_varchar2(
NAME VARCHAR(65535) #错误
);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('文本字符串类型');

在向TEXT类型的字段保存和查询数据时,系统自动按照实际长度存储,不需要预先定义长度。由于实际存储的长度不确定,MySQL 不允许 TEXT 类型的字段做主键。遇到这种情况,只能采用CHAR(M),或者 VARCHAR(M)。

TEXT文本类型,可以存比较大的文本段,搜索速度稍慢,因此如果不是特别大的内容,建议使用CHAR,VARCHAR来代替。还有TEXT类型不用加默认值,加了也没用。而且text和blob类型的数据删除后容易导致“空洞”,使得文件碎片比较多,所以频繁使用的表不建议包含TEXT类型字段,建议单独分出去,单独用一个表。

CREATE TABLE test_text(
tx TEXT
);
INSERT INTO test_text
VALUES('alibaba ');
SELECT CHAR_LENGTH(tx)
FROM test_text; #10

哪些情况使用 CHAR 或 VARCHAR 更好

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

  2. 固定长度的。比如使用uuid作为主键,那用char应该更合适。因为他固定长度,varchar动态根据长度的特性就消失了,而且还要占个长度信息。

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

  4. 具体存储引擎中的情况:

    • MyISAM 最好使用**固定长度(CHAR)**的数据列代替可变长度(VARCHAR)的数据列。这样使得整个表静态化,从而使数据检索更快,用空间换时间。
    • MEMORY 目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系,两者都是作为CHAR类型处理的。
    • InnoDB 建议使用VARCHAR类型。因为对于InnoDB数据表,内部的行存储格式并没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),而且主要影响性能的因素是数据行使用的存储总量,由于char平均占用的空间多于varchar,所以除了简短并且固定长度的,其他考虑varchar。这样节省空间,对磁盘I/O和数据存储总量比较好。

enum类型

ENUM类型也叫作枚举类型,ENUM类型的取值范围需要在定义字段时进行指定。设置字段值时,ENUM类型只允许从成员中选取单个值,不能一次选取多个值。

-- 创建表如下:
-- 添加数据:
CREATE TABLE test_enum(
season ENUM('春','夏','秋','冬','unknow')
);
INSERT INTO test_enum
VALUES('春'),('秋');
# 忽略大小写
INSERT INTO test_enum
VALUES('UNKNOW');
# 允许按照角标的方式获取指定索引位置的枚举值
INSERT INTO test_enum
VALUES('1'),(3);
# Data truncated for column 'season' at row 1
INSERT INTO test_enum
VALUES('ab');
# 当ENUM类型的字段没有声明为NOT NULL时,插入NULL也是有效的
INSERT INTO test_enum
VALUES(NULL);

set类型

SET表示一个字符串对象,可以包含0个或多个成员,但成员个数的上限为64 。设置字段值时,可以取取值范围内的 0 个或多个值。
SET类型在选取成员时,可以一次选择多个成员,这一点与ENUM类型不同。
插入重复的SET类型成员时,MySQL会自动删除重复的成员

-- 创建表:
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;
-- 举例:
CREATE TABLE temp_mul(
gender ENUM('男','女'),
hobby SET('吃饭','睡觉','打豆豆','写代码')
);
INSERT INTO temp_mul VALUES('男','睡觉,打豆豆'); #成功
# Data truncated for column 'gender' at row 1
INSERT INTO temp_mul VALUES('男,女','睡觉,写代码'); #失败
# Data truncated for column 'gender' at row 1
INSERT INTO temp_mul VALUES('妖','睡觉,写代码');#失败
INSERT INTO temp_mul VALUES('男','睡觉,写代码,吃饭'); #成功

二进制字符串类型

BLOB是一个二进制大对象,可以容纳可变数量的数据。
MySQL中的BLOB类型包括TINYBLOBBLOBMEDIUMBLOBLONGBLOB 4种类型,它们可容纳值的最大长度不同。可以存储一个二进制的大对象,比如图片、音频和视频等。

需要注意的是,在实际工作中,往往不会在MySQL数据库中使用BLOB类型存储大对象数据,通常会将图片、音频和视频文件存储到服务器的磁盘上,并将图片、音频和视频的访问路径存储到MySQL中

TEXT和BLOB的使用注意事项:

在使用text和blob字段类型时要注意以下几点,以便更好的发挥数据库的性能。

  1. BLOB和TEXT值也会引起自己的一些问题,特别是执行了大量的删除或更新操作的时候。删除这种值会在数据表中留下很大的"空洞",以后填入这些"空洞"的记录可能长度不同。为了提高性能,建议定期使用 OPTIMIZE TABLE 功能对这类表进行碎片整理
  2. 如果需要对大文本字段进行模糊查询,MySQL 提供了前缀索引。但是仍然要在不必要的时候避免检索大型的BLOB或TEXT值。例如,SELECT * 查询就不是很好的想法,除非你能够确定作为约束条件的WHERE子句只会找到所需要的数据行。否则,你可能毫无目的地在网络上传输大量的值。
  3. 把BLOB或TEXT列分离到单独的表中。在某些环境中,如果把这些数据列移动到第二张数据表中,可以让你把原数据表中的数据列转换为固定长度的数据行格式,那么它就是有意义的。这会减少主表中的碎片,使你得到固定长度数据行的性能优势。它还使你在主数据表上运行SELECT * 查询的时候不会通过网络传输大量的BLOB或TEXT值。

json类型

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式。
在MySQL 5.7中,就已经支持JSON数据类型。在MySQL 8.x版本中,JSON类型提供了可以进行自动验证的JSON文档和优化的存储结构,使得在MySQL中存储和读取JSON类型的数据更加方便和高效。

-- 创建数据表,表中包含一个JSON类型的字段 js
CREATE TABLE test_json(
js json
);
-- 向表中插入JSON数据
INSERT INTO test_json (js)
VALUES ('{"name":"jack", "age":18, "address":{"province":"shanghai","city":"shanghai"}}');
-- 查询t19表中的数据。
SELECT *
FROM test_json;

当需要检索JSON类型的字段中数据的某个具体值时,可以使用**“->”“->>”**符号。

mysql> SELECT js -> '$.name' AS NAME,js -> '$.age' AS age ,js -> '$.address.province'
AS province, js -> '$.address.city' AS city
-> FROM test_json;
+----------+------+-----------+-----------+
| NAME | age | province | city |
+----------+------+-----------+-----------+
| "jack" | 18 | "shanghai" | "shanghai" |
+----------+------+-----------+-----------+

选择建议

在定义数据类型时,如果确定是整数,就用INT ; 如果是小数,一定用定点数类型DECIMAL(M,D) ; 如果是日期与时间,就用 DATETIME
这样做的好处是,首先确保你的系统不会因为数据类型定义出错。不过,凡事都是有两面的,可靠性好,并不意味着高效。
比如,TEXT 虽然使用方便,但是效率不如 CHAR(M) 和 VARCHAR(M)。

字符串的选择:

阿里巴巴《Java开发手册》之MySQL数据库:

  • 任何字段如果为非负数,必须是 UNSIGNED
  • 【强制】小数类型为 DECIMAL,禁止使用 FLOAT 和 DOUBLE。
    说明:在存储的时候,FLOAT 和 DOUBLE 都存在精度损失的问题,很可能在比较值的时候,得到不正确的结果。如果存储的数据范围超过 DECIMAL 的范围,建议将数据拆成整数和小数并分开存储。
  • 【强制】如果存储的字符串长度几乎相等,使用 CHAR 定长字符串类型
  • 【强制】VARCHAR 是可变长字符串,不预先分配存储空间,长度不要超过 5000。如果存储长度大于此值,定义字段类型为 TEXT,独立出来一张表,用主键来对应,避免影响其它字段索引效率

【SQL】之数据类型相关推荐

  1. PL/SQL复合数据类型

    --一.PL/SQL复合数据类型 --(一).PL/SQL记录 --1.定义PL/SQL记录 --(1).定义PL/SQL记录 --Grammar TYPE type_name IS RECORD(f ...

  2. 编译错误 错误:PL/SQL: ORA-00932: 数据类型不一致: 应为 DATE, 但却获得 NUMBER 行

    文章目录 1. 现象 2. 分析 3. 解决方案 通过存储过程将临时B表中的数据同步到轨迹表中 1. 现象 PROCEDURE LABS.ASSET_LOANP 编译错误错误:PL/SQL: ORA- ...

  3. SQL varchar数据类型深入探讨

    In this article we'll review the SQL varchar data type including a basic definition and overview, di ...

  4. SQL Server数据类型概述

    In this article, we will give an overview of various SQL Server data types. 在本文中,我们将概述各种SQL Server数据 ...

  5. sql二进制转十进制_了解SQL十进制数据类型

    sql二进制转十进制 This article aims to walk you through the SQL Decimal data type and its usage with variou ...

  6. SQL DateTime数据类型注意事项和限制

    介绍 (Introduction) In this article, we will explorethe SQL Date Time data type and its limitations. 在 ...

  7. SQL Server 数据类型

    SQL Server 数据类型 本次任务完成时间:2019年05月18日 作者:青青子衿 开发工具与关键技术:SQL Server 2014 Management Studio&& S ...

  8. mysql数据库是什么, mysql数据库的特点, SQL 字段数据类型

    mysql数据库是什么 MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司.      MySQL 是一种关联数据库管理系统,关联数据库将数据保存 ...

  9. mysql和sql server类型_SQL MS Access、MySQL 和 SQL Server 数据类型 - SQL 教程 - 自强学堂...

    SQL MS Access.MySQL 和 SQL Server 数据类型 Microsoft Access.MySQL 和 SQL Server 所使用的数据类型和范围. Microsoft Acc ...

  10. mysql server nchar_SQL MS Access、MySQL 和 SQL Server 数据类型 | w3cschool菜鸟教程

    SQL 用于各种数据库的数据类型 Microsoft Access.MySQL 和 SQL Server 所使用的数据类型和范围. Microsoft Access 数据类型 数据类型 描述 存储 T ...

最新文章

  1. 计算机操作系统第四版习题答案 第一章简答题
  2. [jobdu]调整数组顺序使奇数位于偶数前面
  3. 【数据结构与算法】之深入解析“H指数II”的求解思路与算法示例
  4. java 消息队列服务_ActiveMQ 消息队列服务
  5. psu是什么电脑配件_PSU的完整形式是什么?
  6. activex for chrome扩展程序 下载”_Chrome扩展程序一键生成网页骨架屏
  7. 【剑指Offer】18树的子结构
  8. 如何判断飞机的年限_身边没有懂车朋友如何购买二手车?
  9. 3.5 Java经典垃圾收集器介绍
  10. Macbook M1电脑安装svn及使用
  11. 【制作脑图】万彩脑图大师教程 | 概括主题
  12. Docker部署程序员简历
  13. 一网打尽Mac上的高效工具 - 效率工作篇(附演示视频)
  14. java如何调用手机拍照功能_手把手教你如何实现拍照功能
  15. 各个击破!高效解决游戏开发8大痛点
  16. Qt开发之路59---QPushButton的pressed,released,clicked,toggled响应的区别
  17. Element-UI中打开本地文件
  18. Beta阶段站立会议-02
  19. C语言程序设计十个币,C语言程序设计复习(10页)-原创力文档
  20. 世界上各种壮观震撼奇景。也许你这辈子都看不到了!

热门文章

  1. jQuery仿淘宝精品服饰广告的实现
  2. 电力系统继电保护基础知识
  3. VGG16+UNet个人理解及代码实现(Pytorch)
  4. PyTorch实现 | 车牌OCR识别,《PyTorch深度学习之目标检测》
  5. Ettercap系列IV:闭嘴吧天猫精灵----ettercap过滤器的应用 [Ettercap系列完结撒花]
  6. 本地计算机架设http服务器,Http File Server(简易Http服务器服务端)
  7. 多渠道归因分析:python实现马尔可夫链归因(三)
  8. 猴子吃桃问题——递归算法解答
  9. 计算机科学班(原acm班),计算机科学与技术 培养计划(ACM班)
  10. Pygame游戏飞机大战《星野守望》