Mysql的数据类型-官方文档-学习笔记-数值、日期时间、字符串、json

Mysql的数据类型-官方文档-学习笔记

目录

MySQL 支持几类SQL数据类型:数字类型、日期和时间类型、字符串(字符和字节)类型、空间类型和 JSON数据类型。本章提供了每个类别中类型属性的概述和更详细的描述,以及数据类型存储要求的摘要。

数据类型描述使用以下约定:

  • 对于整数类型,*M*表示最大显示宽度。对于浮点和定点类型, *M*是可以存储的总位数(精度)。对于字符串类型, *M是最大长度。M*的最大允许值取决于数据类型。

  • *D*适用于浮点型和定点型,表示小数点后的位数(小数位数)。最大可能值为 30,但不应大于 M-2。

  • *fsp*适用于 TIMEDATETIMETIMESTAMP类型并表示小数秒精度;也就是说,小数点后的小数部分秒数。该 *fsp*值(如果给定)必须在 0 到 6 的范围内。值 0 表示没有小数部分。如果省略,则默认精度为 0。(这与标准 SQL 默认值 6 不同,以便与以前的 MySQL 版本兼容。)

  • 方括号 ([]) 表示类型定义的可选部分。

1、数值数据类型

1.1 数值数据类型语法

1.2 整数类型(精确值) - INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT

1.3 定点类型(精确值)——DECIMAL、NUMERIC

1.4 浮点类型(近似值)——FLOAT、DOUBLE

1.5 位值类型——BIT

1.6 数值类型属性

1.7 超出范围和溢出处理

MySQL 支持所有标准 SQL 数字数据类型。
这些类型包括精确数值数据类型(INTEGER、 SMALLINT、 DECIMAL 和 NUMERIC ),以及近似数值数据类型(FLOAT、 REAL 和 DOUBLE PRECISION)。
关键字 INT 是 INTEGER 的同义词,
关键字 DEC 和 FIXED 是 DECIMAL 的同义词,
MySQL 将 DOUBLE 视为 DOUBLE PRECISION (非标准扩展)的同义词,
MySQL 也将 REAL 视为 DOUBLE PRECISION (非标准变体)的同义词,除非启用了 REAL_AS_FLOAT 的 SQL 模式。

数据类型 BIT 存储“位”值,并支持 MyISAM、InnoDB、 MEMORY和 NDB表。

1.1 数值数据类型的语法

  • 对于整数数据类型,M表示最大显示宽度。最大显示宽度为 255。显示宽度与类型可以存储的值的范围无关。int(M) 例子: int(4) 表示最大显示4位数字,即个位、十位、百位和千位
  • 对于浮点和定点数据类型, M是可以存储的总位数(包含了小数部分),这里的“位”与bit不是同一个概念,这里的“位”指的是数字的位数,即个位、十位等。
    • 定点:decimal(M[,D]) 例子: decimal(1) 表示mysql只存储1位整数
    • 浮点: float(M[,D]) 例子: float(1) 表示mysql只存储1位整数

如果您为数字列指定 ZEROFILL,MySQL 会自动将 UNSIGNED 属性添加到该列。

数值数据类型允许 UNSIGNED 属性也允许 SIGNED。但是,这些数据类型默认是有符号的,所以 SIGNED 属性没有作用。

SERIAL DEFAULT VALUE 在整数列的定义中是 NOT NULL AUTO_INCREMENT UNIQUE 的别名。

警告
当您在类型为 UNSIGNED 的整数值之间使用减法时,除非启用 NO_UNSIGNED_SUBTRACTION 的 SQL 模式,否则结果是无符号的。

1.1.1 BIT[(M)]

位值类型。M表示每个值的位数,从 164。如果 M省略,则默认为 1

1.1.2 TINYINT[(M)] [UNSIGNED] [ZEROFILL]

一个非常小的整数,占1字节。有符号范围为 -2[^7] = -128 to 2[^7]-1 = 127。无符号范围是 0 to 2[^8]-1 = 255
M 表示最大显示宽度

1.1.3 BOOL, BOOLEAN

这些类型是 TINYINT(1) 的同义词。零值被认为是的。非零值被认为是的:

mysql> SELECT IF(0, 'true', 'false');
+------------------------+
| IF(0, 'true', 'false') |
+------------------------+
| false                  |
+------------------------+

mysql> SELECT IF(1, 'true', 'false');
+------------------------+
| IF(1, 'true', 'false') |
+------------------------+
| true                   |
+------------------------+

mysql> SELECT IF(2, 'true', 'false');
+------------------------+
| IF(2, 'true', 'false') |
+------------------------+
| true                   |
+------------------------+

但是,值TRUEFALSE只是 10 的别名,分别如下所示:

mysql> SELECT IF(0 = FALSE, 'true', 'false');
+--------------------------------+
| IF(0 = FALSE, 'true', 'false') |
+--------------------------------+
| true                           |
+--------------------------------+

mysql> SELECT IF(1 = TRUE, 'true', 'false');
+-------------------------------+
| IF(1 = TRUE, 'true', 'false') |
+-------------------------------+
| true                          |
+-------------------------------+

mysql> SELECT IF(2 = TRUE, 'true', 'false');
+-------------------------------+
| IF(2 = TRUE, 'true', 'false') |
+-------------------------------+
| false                         |
+-------------------------------+

mysql> SELECT IF(2 = FALSE, 'true', 'false');
+--------------------------------+
| IF(2 = FALSE, 'true', 'false') |
+--------------------------------+
| false                          |
+--------------------------------+

最后两个语句显示了2不等于TRUEFALSE的结果,因为 2既不等于 1也不等于0

1.1.4 SMALLINT[(M)] [UNSIGNED] [ZEROFILL]

一个小整数,占2字节。有符号范围为 -2[^15] = -32768 to 2[^15]-1 = 32767 。无符号范围是 0 to 2[^16]-1 = 65535

1.1.5 MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]

一个中等大小的整数,占3字节。有符号范围为 -2[^23] = -8388608 to 2[^23]-1 = 8388607。无符号范围是 0 to 2[^24]-1 = 16777215

1.1.6 INT[(M)] [UNSIGNED] [ZEROFILL]

一个正常大小的整数,占4字节。有符号范围为 -2[^31] = -2147483648 to 2[^31]-1 = 2147483647 。无符号范围是 0 to 2[^32]-1 = 4294967295

1.1.7 INTEGER[(M)] [UNSIGNED] [ZEROFILL]

这种类型是 INT 的同义词。

1.1.8 BIGINT[(M)] [UNSIGNED] [ZEROFILL]

一个大整数,占8字节。有符号范围为 -2[^63] = -9223372036854775808 to 2[^63]-1 = 9223372036854775807 。无符号范围是 0 to 2[^64]-1 = 18446744073709551615

SERIALBIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的别名。

关于列BIGINT ,您应该注意的一些事项 :

  • 所有算术都是使用有符号 BIGINTDOUBLE值完成的,因此您不应使用大于 9223372036854775807(63 位)的无符号大整数,位函数除外!如果你这样做,结果中的最后一些数字可能是错误的,因为在将 BIGINT值转换为 DOUBLE 时会发生舍入错误

    MySQL可以处理BIGINT 的以下几种情况:

  • 始终可以通过使用字符串将其赋值给 BIGINT 列来存储精确的整数值。在这种情况下,MySQL 执行不涉及中间双精度表示的字符串到数字的转换。

  • 当 两个操作数都是整数值时-+、 和 * 运算符使用 BIGINT 算术。这意味着如果您将两个大整数相乘(或返回整数的函数的结果),当结果大于 9223372036854775807 时,您可能会得到意想不到的结果。

1.1.9 DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]

一个压缩的“精确”定点数。

  • *M*是总位数(精度),它的范围是 1 到 65,默认值为 10。
  • D是小数点右侧的数字位数(刻度),它的范围是 0 到 30,并且不能大于M,默认值为 0。
  • 小数点符号和 -(负数)符号不计入 M。如果 *D*为 0,则值没有小数点或小数部分。

DECIMAL 文字文本的长度也有限制;请参阅“表达式处理”。)

如果指定 UNSIGNED,则不允许负值。

所有与 DECIMAL 列的基本计算 ( +, -, *, /) 都以 65 位数字的精度完成。

1.1.10 DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]

这些类型是 DECIMAL 的同义词。 FIXED 同义词可用于与其他数据库系统兼容。

1.1.11 FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]

一个小的(单精度)浮点数。允许的值为-3.402823466E+38 to -1.175494351E-3801.175494351E-38 to 3.402823466E+38。这些是基于 IEEE 标准的理论限制。根据硬件或操作系统,实际范围可能会稍小一些。

M是总位数,D是小数点后的位数。如果省略M 和*D*,则将值存储在硬件允许的范围内。单精度浮点数精确到大约 7 位小数。

FLOAT(M,D) 是一个非标准的 MySQL 扩展。

如果指定 UNSIGNED,则不允许负值。

使用FLOAT可能会给您带来一些意想不到的问题,因为 MySQL 中的所有计算都是以双精度完成的。请参见 “解决没有匹配行的问题”

1.1.12 FLOAT(p) [UNSIGNED] [ZEROFILL]

一个浮点数。p 表示以位为单位的精度,但 MySQL 仅使用此值来确定是使用 FLOAT还是 DOUBLE用于生成的数据类型。如果*p是从 0 到 24,则数据类型变为FLOATM*或 *D*值。如果 *p*是从 25 到 53,则数据类型变为DOUBLEMD 值。结果列的范围与本节前面描述 的单精度FLOAT或双精度 DOUBLE 数据类型相同。

FLOAT(p) 为 ODBC 兼容性提供了语法。`

1.1.13 DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]

一个正常大小(双精度)的浮点数。允许的值为 -1.7976931348623157E+308to -2.2250738585072014E-30802.2250738585072014E-308to 1.7976931348623157E+308。这些是基于 IEEE 标准的理论限制。根据您的硬件或操作系统,实际范围可能会稍小一些。

M是总位数,D是小数点后的位数。如果省略M 和*D*,则将值存储在硬件允许的范围内。双精度浮点数精确到大约 15 位小数。

DOUBLE(M,D) 是一个非标准的 MySQL 扩展。

如果指定 UNSIGNED,则不允许负值。

1.1.14 DOUBLE PRECISION[(M,D)] [UNSIGNED] [ZEROFILL], REAL[(M,D)] [UNSIGNED] [ZEROFILL]

1.2 整数类型(精确值) - INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT

MySQL 支持 SQL 标准整数类型 INTEGER(或INT)和 SMALLINT. 作为标准的扩展,MySQL 还支持整数类型 TINYINTMEDIUMINTBIGINT. 下表显示了每种整数类型所需的存储空间和范围。

表 1.1 MySQL 支持的整数类型所需的存储和范围

类型 存储(字节) 最小值(带符号) 最大值(带符号) 最小值(无符号) 最大值(无符号)
TINYINT 1 -128 127 0 255
SMALLINT 2 -32768 32767 0 65535
MEDIUMINT 3 -8388608 8388607 0 16777215
INT 4 -2147483648 2147483647 0 4294967295
BIGINT 8 -2[^63] 2[^63]-1 0 2[^64]-1

1.3 定点类型(精确值) - DECIMAL、NUMERIC

DECIMALNUMERIC 类型存储精确的数字数据值 。当保持精确的精度很重要时使用这些类型,例如货币数据。在 MySQL 中,NUMERIC被实现为DECIMAL,所以以下关于DECIMAL同样适用于 NUMERIC

MySQL的 DECIMAL 以二进制格式存储值(注意:不是用字符串存储数字字符,因为我一开始以为是字符串),而是将每9个数字字符为一个分段,存储在4字节中,整数与小数部分分开存储,小数也按照每9个数字字符分段,对于分段后不满9个字符的部分,按照最低字节数原则来存储剩余数字。具体如何存储的请参见“精确数学”

DECIMAL列声明中,可以(并且通常)指定精度和小数位数。例如:

salary DECIMAL(5,2)

在本例中,5是精度, 2是小数位数。精度表示为值存储的有效数字的位数,小数位数表示可以存储在小数点后的数字位数。

标准 SQL 要求DECIMAL(5,2)能够存储任何 5 位数字和 2 位小数的值,因此salary 列中可以存储的值范围从-999.99999.99

在标准 SQL 中,语法 DECIMAL(M) 等同于 DECIMAL(M,0) 。 类似地,语法 DECIMAL 等价于 DECIMAL(M,0),其中允许实现来决定 M 的值 。MySQL 支持这两种不同形式的 DECIMAL 语法。M 的默认值为10。

如果小数为 0,则DECIMAL值不包含小数点或小数部分。

DECIMAL 的最大数字位数为65,但给定 DECIMAL 列的实际范围可能受给定列的精度或小数位数限制。如果为此类列分配的值的小数点后位数超过允许的特定小数位数,则该值将转换为该小数位数。(确切的行为是特定于操作系统的,但通常效果是截断到允许的位数。)

1.4 浮点类型(近似值) - FLOAT、DOUBLE

FLOATDOUBLE类型表示近似数值数据值。MySQL 对单精度值使用四个字节,对双精度值使用八个字节。

对于FLOAT,SQL 标准允许在括号中的关键字以位(bit,注意与定点数的数字位不同,此处为二进制位数)为单位指定后面小数的精度(但不是指数范围) ,即FLOAT(p)。 MySQL 也支持这个可选的精度规范,但 FLOAT(p) 的精度值仅用于确定存储大小,从 0 到 23 的精度会产生一个 4 字节的单精度 FLOAT 列。从 24 到 53 的精度会产生一个 8 字节的双精度 DOUBLE 列。

MySQL 允许使用非标准语法: FLOAT(M,D)REAL(M,D) or DOUBLE PRECISION(M,D) 。 在这里,(M,D) 表示总共可以存储最多 M 位数字,其中 D 位数可能在小数点之后。
例如,被定义为 FLOAT(7,4) 的列,显示时的样子为: -999.9999。MySQL 在存储值时会进行舍入,因此如果插入 999.00009FLOAT(7,4) 列中,则近似结果为 999.0001 ,即第4位小数的后面一位数做了四舍五入,将0.00009“五入”为0.00010。

因为浮点值是近似值而不是存储为精确值,所以在比较中尝试将它们视为精确值可能会导致问题。它们还受平台或实现依赖关系的影响。有关更多信息,请参阅 “浮点值问题”

为了获得最大的可移植性,需要存储近似数字数据值的代码应使用FLOATDOUBLE PRECISION不指定精度或位数。

1.5 位值类型 - BIT

BIT数据类型用于存储(二进制)“位”值 。一种 BIT(M) 类型允许存储 M 个二进制位的值。 M 的范围可以从 1 到 64。

要指定“位”的值, 可以使用二进制符号 b'value'b 表示其后跟的是二进制数字,用单引号引起来 , value 是使用 0 和 1 写入的二进制值。例如, b'111'b'10000000' 分别代表十进制的 7128。请参见 “位值文字”

如果将一个长度小于*M*位的值分配给 BIT(M) 列,则该值在左侧用零填充。例如,将 b'101' 的值分配给 BIT(6) 列,由于101 只有3个二进制位,与期待的6位不足,则将左侧填充足够的0以补足6位数字b'000101'存入mysql。

NDB 集群: 给定 NDB 表中使用的所有 BIT 列的最大组合大小不得超过 4096 位。

1.6 数值类型属性

1.6.1 int(M)

int(6) 括号中的6表示最大可“显示”的数字位数,但与存储“bit位数”是不同的概念,它们之间没有关系,也互不影响。
int类型占用4字节,32个二进制位,最大数值是21亿,其完整数字的位数为10位数。int(6)表示告诉应用程序最大显示6位数字,这个“6位”是从右往左开始数,数到第6位,即个位、十位、百位、千位、万位、十万位。
是否支持(6),这取决于应用程序的处理,mysql只是建议最大显示6位数字
如:在int(6)的字段上存入了数字“1234567”,则mysql建议显示6位,即“234567”,但实际显示位多少是应用程序来决定,应用程序可以接受mysql的建议显示后6位,也可以忽略这个建议显示完整的7位数字
这个宽度会随着结果集一起返回给应用程序

1.6.2 UNSIGNED

所有整数类型都可以有一个可选(非标准) UNSIGNED 属性。
无符号类型可用于在列中仅允许非负数,或者当您需要该列的较大数值范围时。例如,如果一列是 INT UNSIGNED ,则该列范围的大小(可表示的数字个数)相同,但其端点向上移动,从原来的1位表示符号和31位表示数值变为0位表示符号(即无符号位)和32位表示数值,可表示的数值范围从 -2147483648 到 2147483647 变为 从 0 到 4294967295 。

浮点和定点类型也可以是 UNSIGNED. 与整数类型一样,此属性可防止将负值存储在列中。与整数类型不同,列值的上限保持不变。

1.6.3 ZEROFILL

如果您为数字列指定 ZEROFILL ,MySQL 会自动添加 UNSIGNED 属性。

1.6.4 AUTO_INCREMENT

整数或浮点数据类型可以具有 AUTO_INCREMENT 属性。当您将 NULL 值插入带有 AUTO_INCREMENT 的索引列时,该列将设置为下一个序列值。通常这是 value+1,其中 value 是表中当前列的最大值。(AUTO_INCREMENT序列以 1 开头)

存储0到 AUTO_INCREMENT 列中的效果与存储 NULL 相同,除非启用了 NO_AUTO_VALUE_ON_ZERO 的 SQL 模式。
如果该列允许为 NULL ,则插入 NULL 到该列不会触发自增,而是将 NULL 插入到该列。
如果插入了一个正整数到该列,则会以该正整数为新的序列,以便下一个自增的值从该新的序列开始顺序排列。

实际操作:

create table tt (
	ID int(2) primary key AUTO_INCREMENT,
	name VARCHAR(1)
);
> OK

insert into tt VALUES (0, 'a'), (3, 'b'), (NULL, 'c');
> Affected rows: 3

select * from tt;
1	a 	# (0, 'a'), 插入id是0,但实际被自动自增为1。因为0与NULL一样都认为是非法的值,这种值遇上 AUTO_INCREMENT 就被认为需要mysql自增得到一个值
3	b 	# (3, 'b'), 指定了3作为id值,实际上3被采纳为ID值了。因为3是一个合法的数值,所以直接采纳,并将 AUTO_INCREMENT 的自增值记录为3,为下次自增做准备
4	c 	# (NULL, 'c'), 插入id是NULL,但实际被自动自增为4。因为上次已经将自增值改为3了,所以本次的自增是3+1=4

AUTO_INCREMENT 并不支持负值的列。

1.7 超出范围和溢出处理

当 MySQL 将值存储在列数据类型允许范围之外的数值列中时,结果取决于当时有效的 SQL 模式:

  • 如果启用严格的 SQL 模式,MySQL 会根据 SQL 标准拒绝超出范围的值并出错,并且插入失败。

  • 如果没有启用限制模式,MySQL 会将值裁剪到列数据类型范围的适当端点,并存储结果值。

    当将超出范围的值分配给整数列时,MySQL 仅存储与该列数据类型范围的对应的范围的值(这句话比较拗口,说人话:MySQL将根据二进制位截断高位,保留低位)。

    当为浮点或定点列分配的值超出指定(或默认)精度和小数位数所表示的范围时,MySQL 仅存储与该范围对应的值。(没太懂到底如何存?)

假设一个表t1有这个定义:

CREATE TABLE t1 (i1 TINYINT, i2 TINYINT UNSIGNED);

启用严格 SQL 模式(strict SQL mode )后,会出现超出范围的错误:

mysql> SET sql_mode = 'TRADITIONAL';
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
ERROR 1264 (22003): Out of range value for column 'i1' at row 1
mysql> SELECT * FROM t1;
Empty set (0.00 sec)

在未启用严格 SQL 模式的情况下,会出现裁剪的警告:

mysql> SET sql_mode = '';
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------+
| Level   | Code | Message                                     |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column 'i1' at row 1 |
| Warning | 1264 | Out of range value for column 'i2' at row 1 |
+---------+------+---------------------------------------------+
mysql> SELECT * FROM t1;
+------+------+
| i1   | i2   |
+------+------+
|  127 |  255 |
+------+------+

未启用严格 SQL 模式时,由于裁剪而发生的列分配转换将报告为ALTER TABLELOAD DATAUPDATE和多行 INSERT语句的警告。
在严格模式下,这些语句会失败,部分或全部值不会被插入或更改,这取决于表是否为事务表等因素。有关详细信息,请参阅 “服务器 SQL 模式”

数值表达式求值期间的溢出会导致错误。例如,最大有符号 BIGINT值为 9223372036854775807,因此以下表达式会产生错误:

mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'

要在这种情况下使操作成功,请将值转换为无符号;

mysql> SELECT CAST(9223372036854775807 AS UNSIGNED) + 1;
+-------------------------------------------+
| CAST(9223372036854775807 AS UNSIGNED) + 1 |
+-------------------------------------------+
|                       9223372036854775808 |
+-------------------------------------------+

是否发生溢出取决于操作数的范围,因此处理上述表达式的另一种方法是使用精确值算术,因为 DECIMAL值的范围比整数更大:

mysql> SELECT 9223372036854775807.0 + 1;
+---------------------------+
| 9223372036854775807.0 + 1 |
+---------------------------+
|     9223372036854775808.0 |
+---------------------------+

整数值之间的减法,其中一个是 UNSIGNED 类型,默认情况下会产生无符号结果。如果结果是负数,则会导致错误:

mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'

如果启用 NO_UNSIGNED_SUBTRACTION SQL 模式,则结果是负数,而不会出现错误:

mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
|                      -1 |
+-------------------------+

如果此类操作的结果用于更新 UNSIGNED整数列,则结果将被裁剪为列类型的最大值,或者如果NO_UNSIGNED_SUBTRACTION 启用,则裁剪为 0。如果启用严格的 SQL 模式,则会发生错误并且列保持不变。

2、日期和时间数据类型 (5种)

2.1 日期和时间数据类型语法

2.2 DATE、DATETIME 和 TIMESTAMP 类型

2.3 TIME 类型

2.4 年份类型

2.5 2 位 YEAR(2) 限制和迁移到 4 位 YEAR

2.6 TIMESTAMP 和 DATETIME 的自动初始化和更新

2.7 时间值中的小数秒

2.8 日期和时间类型之间的转换

2.9 2 位数年份日期

用于表示时间值的日期和时间数据类型是 DATETIMEDATETIMETIMESTAMPYEAR。每种时间类型都有一个有效值范围,以及一个“零”值,当您指定 MySQL 无法表示的无效值时,可以使用该“零”值。TIMESTAMPDATETIME 类型具有特殊的自动更新行为,在 第2.6 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新” 中进行了描述。

有关临时数据类型的存储要求的信息,请参阅 “数据类型存储要求”

有关对时间值进行操作的函数的描述,请参阅 “日期和时间函数”

使用日期和时间类型时,请记住以下一般注意事项:

  • MySQL 以标准输出格式检索给定日期或时间类型的值,但它尝试解释您提供的输入值的各种格式(例如,当您指定要分配给日期或时间类型或与之进行比较的值时)。有关日期和时间类型的允许格式的描述,请参阅 “日期和时间文字”。期待您提供有效值。如果您使用其他格式的值,可能会出现不可预测的结果。

  • 尽管 MySQL 尝试以多种格式解释值,但日期部分必须始终按年-月-日顺序(例如,'98-09-04')给出,而不是按其他地方常用的月-日-年或日-月-年顺序(例如例如'09-04-98',, '04-09-98')。要将其他顺序的字符串转换为年月日顺序,该 STR_TO_DATE()函数可能很有用。

  • 包含 2 位数年份值的日期不明确,因为世纪未知。MySQL 使用以下规则解释 2 位数年份值:

    • 70-99 范围内的年份值变为 1970-1999
    • 00-69 范围内的年份值变为 2000-2069

    另请参见 第 2.9 节,“日期中的两位数年份”

  • 根据 第 2.8 节“日期和时间类型之间的转换” 中的规则,将值从一种时间类型转换为另一种 。

  • 如果值在数字上下文中使用,MySQL 会自动将日期或时间值转换为数字,反之亦然。

  • 默认情况下,当 MySQL 遇到超出范围或对该类型无效的日期或时间类型的值时,它会将值转换为该类型的“零”值。例外情况是超出范围的 TIME值被剪裁到合适的 TIME 范围。

  • 通过将 SQL 模式设置为适当的值,您可以更准确地指定您希望 MySQL 支持的日期类型。(请参阅 “服务器 SQL 模式” 。)您可以通过启用 ALLOW_INVALID_DATES SQL 模式让 MySQL 接受某些日期,例如 '2009-11-31' 。当您想在数据库中存储用户指定的“可能错误的”值(例如,在 Web 表单中)以供将来处理时,这很有用。在这种模式下,MySQL 只验证月份在 1 到 12 的范围内,而日期在 1 到 31 的范围内。

  • MySQL 允许您在 DATE or DATETIME 列中存储日期或月份和日期为零的日期。这对于需要存储您可能不知道确切日期的生日的应用程序很有用。在这种情况下,您只需将日期存储为'2009-00-00''2009-01-00'。但是,对于这些日期,您不应该期望获得正确的结果,例如需要完整日期的 DATE_SUB()DATE_ADD() 函数。要禁止日期中的零月或日部分,请启用该NO_ZERO_IN_DATE 模式。

  • MySQL 允许您将 '0000-00-00' 这样的“零”值存储为“虚拟日期”。在某些情况下,这比使用NULL值更方便,并且使用更少的数据和索引空间。要禁止'0000-00-00',请启用该NO_ZERO_DATE 模式。

  • 通过 Connector/ODBC 使用的“零”日期或时间值会自动转换为 NULL,因为 ODBC 无法处理这些值。

下表显示了每种类型的“零” 值的格式。“零”值是特殊的,但您可以使用表中显示的值显式存储或引用它们。您也可以使用更容易编写的值 '0'0 来表示“零”值。对于包含日期部分( DATEDATETIMETIMESTAMP )的时间类型使用这些值可能会产生警告或错误。确切的行为取决于启用了严格模式和 NO_ZERO_DATE SQL 模式中的哪一个(如果有);请参阅“服务器 SQL 模式”

数据类型 “零”值
DATE '0000-00-00'
TIME '00:00:00'
DATETIME '0000-00-00 00:00:00'
TIMESTAMP '0000-00-00 00:00:00'
YEAR 0000

2.1 日期和时间数据类型语法

用于表示时间值的日期和时间数据类型是DATETIMEDATETIMETIMESTAMPYEAR

对于DATEDATETIME 的范围描述, “ supported ”表示虽然早期的值可能有效(能工作),但不能保证。

MySQL 允许 TIMEDATETIMETIMESTAMP 值的小数秒, 精度高达微秒(6 位数字)。要定义包含小数秒部分的列,请使用语法 type_name(fsp) ,其中 type_nameTIMEDATETIMETIMESTAMPfsp 是小数秒精度。例如:

CREATE TABLE t1 (t TIME(3), dt DATETIME(6), ts TIMESTAMP(0));

该*fsp*值(如果给定)必须在 0 到 6 的范围内。值 0 表示没有小数部分。如果省略,则默认精度为 0。(这与标准 SQL 默认值 6 不同,以便与以前的 MySQL 版本兼容。)

表中的任何TIMESTAMPDATETIME列都可以具有自动初始化和更新属性;请参阅 第 2.6 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”

2.1.1 DATE

日期。 “ supported ”的范围是 '1000-01-01' to '9999-12-31'。MySQL 以 ‘YYYY-MM-DD’ 格式显示 DATE 的值 ,但允许使用字符串数字将值分配给 DATE 列。

2.1.2 DATETIME[(fsp)]

日期和时间组合。“ supported ”的范围是 '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'。MySQL 以 'YYYY-MM-DD hh:mm:ss[.fraction]' 格式显示 DATETIME 值 ,但允许使用字符串或数字将值分配给 DATETIME 列。

可选值 *fsp*可以给出 0 到 6 范围的数字来指定小数秒精度。值 0 表示没有小数部分。如果省略,则默认精度为 0。

可以使用 DEFAULTON UPDATE 列定义子句指定 DATETIME 列的自动初始化和更新到当前日期和时间 ,如 第 2.6 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新” 中所述。

2.1.3 TIMESTAMP[(fsp)]

时间戳。范围是'1970-01-01 00:00:01.000000'UTC 到'2038-01-19 03:14:07.999999'UTC。 TIMESTAMP 值存储为自纪元epoch ( '1970-01-01 00:00:00' UTC)TIMESTAMP以来的秒数。时间戳不能表示值'1970-01-01 00:00:00',因为这相当于从 epoch 开始的 0 秒,但值 0 是用于表示'0000-00-00 00:00:00' 这个“零”值的保留值。

可选值 *fsp*可以给出 0 到 6 范围的数字来指定小数秒精度。值 0 表示没有小数部分。如果省略,则默认精度为 0。

服务器处理TIMESTAMP 定义的方式取决于 explicit_defaults_for_timestamp 系统变量的值(参见 “服务器系统变量” )。

  • 如果 explicit_defaults_for_timestamp 启用,则不会自动将 DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP属性分配给任何 TIMESTAMP列。它们必须明确包含在列定义中。此外,任何 TIMESTAMP 列如果未明确声明为NOT NULL 则允许为 NULL值。

  • 如果 explicit_defaults_for_timestamp 禁用,服务器处理TIMESTAMP 如下:
    除非另有说明,否则如果没有明确分配一个值给 Table 中的第一个 TIMESTAMP列,则该列将自动设置为最近修改的日期和时间。这使得 TIMESTAMP 列对于记录 INSERTor UPDATE操作的时间戳很有用。您还可以通过为其分配一个 NULL 值来将 TIMESTAMP 列设置为当前日期和时间,除非它已定义为允许 NULL值。

可以使用DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP列定义子句指定自动初始化和更新到当前日期和时间。TIMESTAMP 如前所述,默认情况下,第一列具有这些属性。但是,TIMESTAMP可以将表中的任何列定义为具有这些属性。

2.1.4 TIME[(fsp)]

时间。范围是 '-838:59:59.000000' to '838:59:59.000000'。MySQL 以 ‘hh:mm:ss[.fraction]’ 格式显示 TIME 的值 ,但允许使用字符串数字将值分配给 TIME 列。

可选值 *fsp*可以给出 0 到 6 范围的数字来指定小数秒精度。值 0 表示没有小数部分。如果省略,则默认精度为 0。

2.1.5 YEAR[(4)]

4 位数格式的年份。MySQL 以 YYYY 格式显示 YEAR 值 ,但允许使用字符串或数字将值分配给 YEAR 列。YEAR 值显示成: 190121550000

注意:

MySQL 5.7.5 中已弃用该YEAR(2)数据类型并删除了对它的支持。要将 2 位列转换YEAR(2) 为 4位列YEAR ,请参阅第 2.5 节,“2 位 YEAR(2) 限制和迁移到 4 位 YEAR”

有关 YEAR显示格式和输入值解释的更多信息,请参阅第 2.4 节,“YEAR 类型”

2.1.6 时间值的额外说明

聚合函数SUM()AVG() 不适用于时间值。(他们将值转换为数字,在第一个非数字字符之后丢失所有内容。)要解决此问题,请转换为数字单位,执行聚合操作,然后转换回时间值。例子:

SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col))) FROM tbl_name;
SELECT FROM_DAYS(SUM(TO_DAYS(date_col))) FROM tbl_name;

注意:

MySQL 服务器在启用 MAXDB SQL 模式的情况下,TIMESTAMPDATETIME 相同。如果在创建表时启用此模式,则将 TIMESTAMP列创建为DATETIME列。因此,此类列使用 DATETIME显示格式,具有相同的值范围,并且不会自动初始化或更新到当前日期和时间。请参阅 “服务器 SQL 模式”

自 MySQL 5.7.22 起,MAXDB已弃用;将在 MySQL 的未来版本中删除。

2.2 DATE、DATETIME 和 TIMESTAMP 类型

DATEDATETIMETIMESTAMP 类型是相关的。 本节介绍它们的特征、它们的相似之处以及它们的不同之处。MySQL 可以识别 DATEDATETIMETIMESTAMP 的多种格式的值,更多信息参考 “日期和时间文字” 。对于 DATEDATETIME 范围描述,“ supported ”表示虽然早期的值可能有效,但不能保证。

DATE类型用于具有日期部分但没有时间部分的值。 MySQL 以 'YYYY-MM-DD' 格式检索和显示 DATE 类型的值 。支持的范围是 '1000-01-01' to '9999-12-31'

DATETIME类型用于同时包含日期和时间部分的值。MySQL 以 'YYYY-MM-DD hh:mm:ss' 格式检索和显示 DATETIME值 。支持的范围是 '1000-01-01 00:00:00' to '9999-12-31 23:59:59'

TIMESTAMP 类型用于同时包含日期和时间部分的值 。TIMESTAMP具有'1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC 的范围。

一个DATETIMETIMESTAMP 值可以包括一个尾随小数秒部分,精度高达微秒(6 位)。特别是,插入到DATETIMETIMESTAMP列中的值中的任何小数部分都将被存储而不是被丢弃。包含小数部分后,这些值的格式是 'YYYY-MM-DD hh:mm:ss[.fraction]'DATETIME 类型值的范围是 '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'TIMESTAMP 类型值的范围是 '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999' 。小数部分应始终与其余时间用小数点分隔;不识别其他小数秒分隔符。有关 MySQL 中小数秒支持的信息,请参阅 第 2.7 节,“时间值中的小数秒”

TIMESTAMPDATETIME 数据类型提供自动初始化和更新到当前日期和时间。有关更多信息,请参阅 第 2.6 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”

MySQL 将TIMESTAMP值从当前时区转换为 UTC 进行存储,然后从 UTC 转换回当前时区进行检索。(这不会发生在其他类型,例如DATETIME.)默认情况下,每个连接的当前时区是服务器的时间。可以基于每个连接设置时区。只要时区设置保持不变,您就可以返回存储的相同值。如果您存储一个TIMESTAMP值,然后更改时区并检索该值,则检索到的值与您存储的值不同。发生这种情况是因为没有使用同一时区进行双向转换。当前时区可用作time_zone系统变量。有关更多信息,请参阅 “MySQL 服务器时区支持”
如果 SQL 模式允许这种转换,则 无效 DATEDATETIMETIMESTAMP 值将转换为相应类型的“零”值('0000-00-00' or '0000-00-00 00:00:00')。确切的行为取决于是否启用了严格 SQL 模式和 NO_ZERO_DATE SQL 模式中的哪一个;请参阅 “服务器 SQL 模式”

请注意 MySQL 中日期值解释的某些属性:

  • MySQL 允许将值指定为字符串的“宽松”(relaxed)格式,其中任何标点符号都可以用作日期部分或时间部分之间的分隔符。在某些情况下,这种语法可能具有欺骗性。例如,值'10:11:12'可能看起来像时间值因为使用了:,但如果在日期上下文中使用,则 '2010-11-12' 被解释为年份。该值 '10:45:15'将被转换为 '0000-00-00'因为 '45'不是有效月份。

    日期和时间部分与小数秒部分之间唯一可识别的分隔符是小数点。

  • 服务器要求月份和日期值有效,而不仅仅是分别在 1 到 12 和 1 到 31 的范围内。'2004-04-31'在禁用严格模式的情况下,将转换为 无效日期 '0000-00-00'并生成警告,因为4月没有31号。启用严格模式后,无效日期会产生错误。要允许此类日期,请启用 ALLOW_INVALID_DATES. 有关详细信息,请参阅 “服务器 SQL 模式”

  • MySQL 不接受 TIMESTAMP 在日或月列中包含零的值或不是有效日期的值。如果 SQL 模式允许此值,则此规则的唯一例外是特殊的“零”值 。'0000-00-00 00:00:00' 确切的行为取决于是否启用了严格 SQL 模式和 NO_ZERO_DATE SQL 模式中的哪一个;请参阅 “服务器 SQL 模式”

  • 包含 2 位数年份值的日期不明确,因为世纪未知。MySQL 使用以下规则解释 2 位数年份值:

    • 范围内的年份值00-69变为 2000-2069
    • 范围内的年份值70-99变为 1970-1999

另请参见 第 2.9 节,“日期中的两位数年份”

2.3 TIME 类型

MySQL以 'hh:mm:ss' 格式(或 'hhh:mm:ss' 大“小时”值的格式)检索和显示 TIME 值。TIME值的范围可以从 '-838:59:59''838:59:59'。小时部分可能很大,因为该TIME类型不仅可以用于表示一天中的某个时间(必须小于 24 小时),还可以用于表示经过的时间或两个事件之间的时间间隔(可能远大于 24小时,甚至负数)。

MySQL 可以识别TIME几种格式的值,其中一些可以包括一个尾随小数秒部分,精度高达微秒(6 位)。请参阅 “日期和时间文字”。有关 MySQL 中小数秒支持的信息,请参阅 第 2.7 节,“时间值中的小数秒”。特别是,插入到 TIME 列中的值中的任何小数部分都会被存储而不是被丢弃。包含小数部分后, TIME 值的范围为'-838:59:59.000000''838:59:59.000000'

TIME 列分配缩写的时间值时要小心 。MySQL 将带有冒号的时间缩写值解释为一天中的时间。也就是说,'11:12'意味着 '11:12:00',不是 '00:11:12'。MySQL 使用最右边的两个数字表示秒(即,作为经过的时间而不是一天中的时间)的假设来解释不带冒号的缩写值。例如,您可能将 '1112'1112 视为 '11:12:00'(11 点后 12 分钟),但 MySQL 将它们解释为'00:11:12'(11 分钟,12 秒)。同样,'12'12被解释为 '00:00:12'。(个人总结:带冒号的时间值从左到右按“时分秒”的顺序解析,不带冒号的纯数字时间值从右到左按“秒分时”的顺序解析)

在时间部分和小数秒部分之间识别的唯一分隔符是小数点。

默认情况下,位于TIME 范围之外但在其他方面有效的值将被剪裁到范围的最近端点。例如, '-850:00:00'and '850:00:00'被转换为 '-838:59:59'and '838:59:59'。无效TIME 值转换为'00:00:00'. 请注意,因为'00:00:00'它本身是一个有效值 TIME,所以无法根据存储在表中的 '00:00:00' 值来判断是原始值无效转换而来,还是原始值就是 '00:00:00'

要对无效 TIME 值进行更严格的处理,请启用严格的 SQL 模式以导致错误发生。请参阅 “服务器 SQL 模式”

2.4 年份类型

YEAR 类型是用于表示年份值的 1 字节类型。可以将其声明为 YEAR具有 4 个字符的隐式显示宽度,或者等效地声明为YEAR(4)具有显式显示宽度。

注意

2 位 YEAR(2) 数据类型已被弃用,并且在 MySQL 5.7.5 中删除了对它的支持。要将 2 位 YEAR(2) 列转换为 4 位 YEAR 列,请参阅 第 2.5 节,“2 位 YEAR(2) 限制和迁移到 4 位 YEAR”

MySQL 以 YYYY 格式显示 YEAR 值, 范围为 1901 to21550000.

YEAR接受多种格式的输入值:

  • '1901''2155' 范围内的 4 位字符串

  • 19012155 范围内的 4 位数字

  • '0''99' 范围内 的 1 位或 2 位字符串。MySQL 将 '0' to '69' 范围的值转换为 20002069YEAR 值,将 '70'to'99' 范围的值转换为 19701999YEAR 值。

  • 099 范围内 的 1 位或 2 位数字。MySQL 将 1 to 69 范围的值转换为 20012069YEAR 值,将 70to99 范围的值转换为 19701999YEAR 值。

    插入数字0 具有显示值为0000 和内部值为0000 的结果。如果想插入零并将其解释为2000,请将其指定为字符串 '0''00'

  • 作为返回 YEAR 上下文中可接受的值的函数的结果,例如 NOW()

如果未启用严格 SQL 模式,MySQL 会将无效 YEAR值转换为0000. 在严格的 SQL 模式下,尝试插入无效 YEAR值会产生错误。

另请参见第 2.9 节,“日期中的两位数年份”

2.5 2 位 YEAR(2) 限制和迁移到 4 位 YEAR

本节介绍使用 2 位YEAR(2)数据类型时可能出现的问题,并提供有关将现有 YEAR(2)列转换为 4 位年份值列的信息,可以将其声明为 YEAR 隐式显示宽度为 4 个字符,或等效地声明YEAR(4)为显式显示宽度。

尽管 YEAR/YEAR(4) 和废弃的YEAR(2)类型的内部值范围相同(1901 to 21550000),但显示宽度 YEAR(2)使该类型内在的歧义,因为显示的值仅指示内部值的最后两位数字并省略世纪数字。在某些情况下,结果可能会导致信息丢失。出于这个原因,请避免 YEAR(2)在您的应用程序中使用并在需要year值数据类型的任何地方使用YEAR/YEAR(4)。从 MySQL 5.7.5 开始,移除对 YEAR(2) 的支持,现有的 2 位列YEAR(2) 必须转换为 4 位 YEAR列再次可用。

2.5.1 YEAR(2) 的限制

YEAR(2) 数据类型的问题包括显示值的歧义,以及在转储和重新加载值或转换为字符串时可能丢失信息。

  • 显示YEAR(2)的值可能不明确。最多三个 YEAR(2)具有不同内部值的值可能具有相同的显示值,如以下示例所示:

    mysql> CREATE TABLE t (y2 YEAR(2), y4 YEAR);
    Query OK, 0 rows affected, 1 warning (0.01 sec)
    
    mysql> INSERT INTO t (y2) VALUES(1912),(2012),(2112);
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> UPDATE t SET y4 = y2;
    Query OK, 3 rows affected (0.00 sec)
    Rows matched: 3  Changed: 3  Warnings: 0
    
    mysql> SELECT * FROM t;
    +------+------+
    | y2   | y4   |
    +------+------+
    |   12 | 1912 |
    |   12 | 2012 |
    |   12 | 2112 |
    +------+------+
    3 rows in set (0.00 sec)
    
  • 如果您使用 mysqldump 转储前面示例中创建的表,则转储文件y2使用相同的 2 位 ( 12) 表示所有值。如果从转储文件重新加载表,所有生成的行都有内部值为 2012 且显示值为 12,从而失去它们之间的区别。

  • 将 2 位或 4 位 YEAR数据值转换为字符串形式使用其数据类型显示宽度。假设一个 YEAR(2) 列和一个 YEAR/YEAR(4) 列都包含 1970 值。则它们各自将得到 '70''1970' 的字符串结果。也就是说,从内部值到字符串的转换会丢失信息。

  • 插入到一个 CSV 表中的 YEAR(2) 列时,在19702069 范围之外的值存储将不正确。例如,插入 2211 会导致显示值为 11 ,但内部值为 2011

要避免这些问题,请使用 4 位 YEARYEAR(4)数据类型而不是 2 位YEAR(2)数据类型。关于迁移策略的建议出现在本节后面。

(TODO: 未完成)

2.6 TIMESTAMP 和 DATETIME 的自动初始化和更新

TIMESTAMPDATETIME列可以自动初始化并更新为当前日期和时间(即当前时间戳)。

对于表中的任何TIMESTAMPDATETIME列,您可以将当前时间戳指定为默认值、自动更新值:

  • 自动初始化的列设置为插入的行的当前时间戳,这些行没有为该列指定值。
  • 当行中任何其他列的值从其当前值更改时,自动更新的列会自动更新为当前时间戳。如果所有其他列都设置为其当前值,则自动更新的列保持不变。要防止自动更新的列在其他列更改时更新,请将其显式设置为其当前值。要在其他列未更改的情况下更新自动更新的列,请将其显式设置为应具有的值(例如,将其设置为 CURRENT_TIMESTAMP)。

此外,如果 explicit_defaults_for_timestamp 系统变量被禁用,您可以通过为其分配一个值来将任何 TIMESTAMP(但不是 DATETIME)列初始化或更新为当前日期和时间NULL,除非它已定义为允许NULL值。

要指定自动属性,请在列定义中使用DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP 子句。子句的顺序无关紧要。如果两者都存在于列定义中,则任何一个都可以先出现。 CURRENT_TIMESTAMP 的任何同义词都与 CURRENT_TIMESTAMP 具有相同的含义。它们是 CURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(), LOCALTIMESTAMP, 和 LOCALTIMESTAMP()

(TODO: 未完成,剩下的是NULL值、默认值的详细说明)

2.7 时间值中的小数秒

2.8 日期和时间类型之间的转换

2.9 2 位数年份日期

3、字符串数据类型

3.1 字符串数据类型语法

3.2 CHAR 和 VARCHAR 类型

3.3 BINARY 和 VARBINARY 类型

3.4 BLOB 和 TEXT 类型

3.5 ENUM 类型

3.6 SET 类型

3.1 字符串数据类型语法

3.2 CHAR 和 VARCHAR 类型

3.3 BINARY 和 VARBINARY 类型

3.4 BLOB 和 TEXT 类型

3.5 ENUM 类型

3.6 SET 类型

4、空间数据类型

4.1 空间数据类型

4.2 OpenGIS 几何模型

4.3 支持的空间数据格式

4.4 几何良构性和有效性

4.5 创建空间列

4.6 填充空间列

4.7 获取空间数据

4.8 优化空间分析

4.9 创建空间索引

4.10 使用空间索引

4.1 空间数据类型

4.2 OpenGIS 几何模型

4.3 支持的空间数据格式

4.4 几何良构性和有效性

4.5 创建空间列

4.6 填充空间列

4.7 获取空间数据

4.8 优化空间分析

4.9 创建空间索引

4.10 使用空间索引

5、JSON 数据类型

5.1、创建 JSON 值
5.2、JSON 值的规范化、合并和自动包装
5.3、搜索和修改 JSON 值
5.4、JSON 路径语法
5.5、JSON值的比较和排序
5.6、在 JSON 和非 JSON 值之间转换
5.7、JSON 值的聚合
5.8、相关参考

从 MySQL 5.7.8 开始,MySQL 支持由 RFC 7159 定义的本地 JSON 数据类型 ,可以有效地访问 JSON(JavaScript Object Notation)文档中的数据。与将 JSON 格式的字符串存储在字符串列中相比,该数据类型具有以下优势:

  • 自动验证存储在 JSON列中的 JSON 文档。无效的文档会产生错误。
  • 优化的存储格式。存储在 JSON 列中的 JSON 文档被转换为允许快速读取文档元素的内部格式。当服务器稍后必须读取以这种二进制格式存储的 JSON 值时,不需要从文本表示中解析该值。二进制格式的结构使服务器能够直接通过键或数组索引查找子对象或嵌套值,而无需读取文档中它们之前或之后的所有值。

存储 JSON 文档所需的空间与 LONGBLOBLONGTEXT 大致相同; 有关详细信息,请参阅 第 7 节,“数据类型存储要求”。请务必记住,存储在JSON列中的任何 JSON 文档的大小都受限于max_allowed_packet系统变量的值。(当服务器在内存中内部操作 JSON 值时,它可以大于此值;该限制适用于服务器存储它时。)

JSON不能有非NULL默认值。

除了JSON数据类型,还有一组 SQL 函数可用于启用对 JSON 值的操作,例如创建、操作和搜索。以下讨论显示了这些操作的示例。有关各个函数的详细信息,请参阅第 12.18 节,“JSON 函数”

还提供了一组用于对 GeoJSON 值进行操作的空间函数。请参阅“空间 GeoJSON 函数”

JSON列,与其他二进制类型的列一样,不直接索引;相反,您可以在生成的列上创建一个索引,从该 JSON列中提取一个标量值。有关详细示例, 请参阅 索引生成的列以提供 JSON 列索引。

MySQL 优化器还在匹配 JSON 表达式的虚拟列上查找兼容索引。

MySQL NDB Cluster 7.5(7.5.2 和更高版本)支持 JSON列和 MySQL JSON 函数,包括在从列生成的 JSON列上创建索引作为无法索引JSON列的解决方法。每个 NDB 表最多支持 3个 JSON列 。

接下来的几节提供有关 JSON 值的创建和操作的基本信息。

5.1、创建 JSON 值

JSON 数组包含由逗号分隔并包含在[] 字符中的值列表:

["abc", 10, null, true, false]

JSON 对象包含一组键值对,由逗号分隔并包含在{ }字符中:

{
    
    "k1": "value", "k2": 10}

如示例所示,JSON 数组和对象可以包含标量值,即字符串或数字、JSON 空字面量或 JSON 布尔真或假字面量。JSON 对象中的键必须是字符串。时间(日期、时间或日期时间)标量值也是允许的:

["12:18:29.000000", "2015-07-29", "2015-07-29 12:18:29.000000"]

在 JSON 数组元素和 JSON 对象键值中允许嵌套:

[99, {
    
    "id": "HK500", "cost": 75.99}, ["hot", "cold"]]
{
    
    "k1": "value", "k2": [10, 20]}

您还可以从 MySQL 为此目的提供的许多函数中获取 JSON 值(请参阅 第 12.18.2 节,“创建 JSON 值的函数”)以及将其他类型的值使用 CAST(value AS JSON) (请参阅 JSON 之间的转换)和非 JSON 值)转换为JSON类型 。接下来的几段描述了 MySQL 如何处理作为输入提供的 JSON 值。

在 MySQL 中,JSON 值被写为字符串。MySQL 解析在需要 JSON 值的上下文中使用的任何字符串,如果它作为 JSON 无效,则会产生错误。这些上下文包括将值插入到具有 JSON数据类型的列中,并将参数传递给需要 JSON 值的函数(通常显示为 *json_doc*或 *json_val*在 MySQL JSON 函数的文档中显示),如以下示例所示:

  • 如果值是有效的 JSON 值,则尝试将值插入JSON 列能成功,但如果不是,则失败:
mysql> CREATE TABLE t1 (jdoc JSON);
Query OK, 0 rows affected (0.20 sec)

mysql> INSERT INTO t1 VALUES('{"key1": "value1", "key2": "value2"}');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO t1 VALUES('[1, 2,');
ERROR 3140 (22032) at line 2: Invalid JSON text: 
"Invalid value." at position 6 in value (or column) '[1, 2,'.

在此类错误消息中,“ at position N ”的位置是从 0 开始的,但只能将其视为在值中实际发生问题的位置的粗略指示。

  • JSON_TYPE()函数需要一个 JSON 参数并尝试将其解析为 JSON 值。如果有效,将返回 JSON 类型的值,否则产生错误:

    mysql> SELECT JSON_TYPE('["a", "b", 1]');
    +----------------------------+
    | JSON_TYPE('["a", "b", 1]') |
    +----------------------------+
    | ARRAY                      |
    +----------------------------+
    
    mysql> select json_type('{}');
    +-----------------+
    | json_type('{}') |
    +-----------------+
    | OBJECT          |
    +-----------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_TYPE('"hello"');
    +----------------------+
    | JSON_TYPE('"hello"') |
    +----------------------+
    | STRING               |
    +----------------------+
    
    mysql> SELECT JSON_TYPE('hello');
    ERROR 3146 (22032): Invalid data type for JSON data in argument 1
    to function json_type; a JSON string or JSON type is required.
    

    MySQL 使用 utf8mb4 字符集(character set) 和 utf8mb4_bin 字符序(collation,字符排序规则,bin表示用编码值进行比较) 规则处理 JSON 上下文中使用的字符串。其他字符集中的字符串根据需要转换utf8mb4为。(对于asciior utf8字符集中的字符串,不需要转换,因为asciiandutf8utf8mb4 的子集。)

说明(自己补充)

collation,字符排序规则。_bin 表示用编码值(二进制)进行比较,_ci 表示大小写不敏感(Insensitive),_cs 表示大小写敏感

也可以指定字符串的值是否区分大小写,与mysql的表名称是否区分大小写不同。

CREATE TABLE `t` (
  `id` int(11) DEFAULT NULL,
  `s1` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `s2` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 插入两个数据,一个大写的Sql,一个小写的sql
mysql> insert into t values (NULL,'Sql','Sql'), (NULL,'sql','sql');
Query OK, 2 rows affected (0.04 sec)

# 查询所有数据:只有两条数据
mysql> select * from t;
+----+------+------+
| id | s1   | s2   |
+----+------+------+
|  1 | Sql  | Sql  |
|  2 | sql  | sql  |
+----+------+------+
2 rows in set (0.00 sec)

# 查询 _bin 编码值的字段,这是区分大小写的,所以只能得到小写sql的那一条数据
mysql> select * from t where s1 = 'sql';
+----+------+------+
| id | s1   | s2   |
+----+------+------+
|  2 | sql  | sql  |
+----+------+------+
1 row in set (0.00 sec)

# 查询 _ci 不区分大小写的字段,所以能查询到大写的Sql和小写的sql,共两条数据
mysql> select * from t where s2 = 'sql';
+----+------+------+
| id | s1   | s2   |
+----+------+------+
|  1 | Sql  | Sql  |
|  2 | sql  | sql  |
+----+------+------+
2 rows in set (0.00 sec)

作为使用文字字符串编写 JSON 值的替代方法,存在用于从组件元素组合 JSON 值的函数。JSON_ARRAY()接受一个(可能是空的)值列表并返回一个包含这些值的 JSON 数组:

mysql> SELECT JSON_ARRAY('a', 1, NOW());
+----------------------------------------+
| JSON_ARRAY('a', 1, NOW())              |
+----------------------------------------+
| ["a", 1, "2015-07-27 09:43:47.000000"] |
+----------------------------------------+

JSON_OBJECT()获取一个(可能为空的)键值对列表并返回一个包含这些对的 JSON 对象:

mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc');
+---------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc') |
+---------------------------------------+
| {
   
   "key1": 1, "key2": "abc"}            |
+---------------------------------------+

JSON_MERGE()接受两个或多个 JSON 文档并返回组合结果:

mysql> SELECT JSON_MERGE('["a", 1]', '{"key": "value"}');
+--------------------------------------------+
| JSON_MERGE('["a", 1]', '{"key": "value"}') |
+--------------------------------------------+
| ["a", 1, {
   
   "key": "value"}]                 |
+--------------------------------------------+

有关合并规则的信息,请参阅 JSON 值的规范化、合并和自动包装

JSON 值可以分配给用户定义的变量:

mysql> SET @j = JSON_OBJECT('key', 'value');
mysql> SELECT @j;
+------------------+
| @j               |
+------------------+
| {
   
   "key": "value"} |
+------------------+

# 以下为我自己的测试。结论:@j的类型是longtext,而不是json类型
mysql> create table test select @j;
Query OK, 1 row affected (0.09 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> desc test;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| @j    | longtext | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
1 row in set (0.03 sec)

但是,用户定义的变量不能是 JSON 数据类型,因此虽然 @j 在前面的示例中看起来像 JSON 值并且具有与 JSON 值相同的字符集和排序规则,但它没有 JSON 数据类型。相反, JSON_OBJECT() 的结果在分配给变量时被转换为字符串(我实测被转换为 longtext 类型了)。

通过转换 JSON 值生成的字符串有一个字符集 utf8mb4 和一个排序规则 utf8mb4_bin

mysql> SELECT CHARSET(@j), COLLATION(@j);
+-------------+---------------+
| CHARSET(@j) | COLLATION(@j) |
+-------------+---------------+
| utf8mb4     | utf8mb4_bin   |
+-------------+---------------+

因为 utf8mb4_bin 是二进制排序规则,所以 JSON 值的比较区分大小写。

# json字段区分大小写,但普通的字符串字段是不区分大小写
mysql> SELECT JSON_ARRAY('x') = JSON_ARRAY('X'), 'x' = 'X';
+-----------------------------------+-----------+
| JSON_ARRAY('x') = JSON_ARRAY('X') | 'x' = 'X' |
+-----------------------------------+-----------+
|                                 0 |         1 |
+-----------------------------------+-----------+
1 row in set (0.00 sec)

区分大小写也适用于 JSON 的 nulltruefalse 字符,它们必须始终以小写形式编写:

mysql> SELECT JSON_VALID('null'), JSON_VALID('Null'), JSON_VALID('NULL');
+--------------------+--------------------+--------------------+
| JSON_VALID('null') | JSON_VALID('Null') | JSON_VALID('NULL') |
+--------------------+--------------------+--------------------+
|                  1 |                  0 |                  0 |
+--------------------+--------------------+--------------------+

mysql> SELECT CAST('null' AS JSON);
+----------------------+
| CAST('null' AS JSON) |
+----------------------+
| null                 |
+----------------------+
1 row in set (0.00 sec)

mysql> SELECT CAST('NULL' AS JSON);
ERROR 3141 (22032): Invalid JSON text in argument 1 to function cast_as_json:
"Invalid value." at position 0 in 'NULL'.

JSON 字符的区分大小写与 SQL NULLTRUEFALSE 字符的区分大小写不同,后者可以用任何字母大小写:

mysql> SELECT ISNULL(null), ISNULL(Null), ISNULL(NULL);
+--------------+--------------+--------------+
| ISNULL(null) | ISNULL(Null) | ISNULL(NULL) |
+--------------+--------------+--------------+
|            1 |            1 |            1 |
+--------------+--------------+--------------+

有时可能需要或希望将引号字符 (双引号"或单引号') 插入 JSON 文档。对于此示例,假设您希望将一些 JSON 对象插入到使用此处所示的 SQL 语句创建的表中,其中包含表示语句的字符串,这些字符串表示有关 MySQL 的一些实际的,每个都与适字符串当的关键字配对:

mysql> CREATE TABLE facts (sentence JSON);

# 假设要插入json:mascot: The MySQL mascot is a dolphin named "Sakila".
# 使用 MySQL函数 JSON_OBJECT() 将其作为 JSON 对象插入到 facts 表中,必须使用反斜杠转义每个引号字符:
mysql> INSERT INTO facts VALUES
     >   (JSON_OBJECT("mascot", "Our mascot is a dolphin named \"Sakila\"."));

# 如果您将值作为 JSON 对象文字插入,则这不会以相同的方式工作,在这种情况下,您必须使用双反斜杠转义序列,如下所示:
mysql> INSERT INTO facts VALUES
     >   ('{"mascot": "Our mascot is a dolphin named \\"Sakila\\"."}');

# 使用双反斜杠可以防止 MySQL 执行转义序列处理,而是使其将字符串文字传递给存储引擎进行处理。在以刚才显示的任何一种方式插入 JSON 对象后,您可以通过执行简单的 SELECT 来看到反斜杠出现在 JSON 列值中,如下所示:
mysql> SELECT sentence FROM facts;
+---------------------------------------------------------+
| sentence                                                |
+---------------------------------------------------------+
| {
   
   "mascot": "Our mascot is a dolphin named \"Sakila\"."} |
+---------------------------------------------------------+

要查找这个 mascot用作键的特定句子,您可以使用 column-path 运算符 ->,如下所示:

mysql> SELECT sentence->"$.mascot" FROM facts;
+---------------------------------------------+
| sentence->"$.mascot"                        |
+---------------------------------------------+
| "Our mascot is a dolphin named \"Sakila\"." |
+---------------------------------------------+
1 row in set (0.00 sec)

这使反斜杠以及周围的引号保持不变。要使用作为键显示所需的值 mascot,但不包括周围的引号或任何转义符,请使用内联路径运算符 ->>,如下所示:

mysql> SELECT sentence->>"$.mascot" FROM facts;
+-----------------------------------------+
| sentence->>"$.mascot"                   |
+-----------------------------------------+
| Our mascot is a dolphin named "Sakila". |
+-----------------------------------------+

# 我实测报错:
mysql> SELECT sentence->>"$.mascot" FROM facts;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '>"$.mascot" FROM facts' at line 1

笔记

如果启用了服务器 NO_BACKSLASH_ESCAPES SQL 模式 ,前面的示例将无法正常工作 。如果设置了此模式,则可以使用单反斜杠而不是双反斜杠来插入 JSON 对象文字,并且保留反斜杠。如果JSON_OBJECT()在执行插入时使用该函数并且设置了此模式,则必须交替使用单引号和双引号,如下所示:

mysql> INSERT INTO facts VALUES
     > (JSON_OBJECT('mascot', 'Our mascot is a dolphin named "Sakila".'));

有关此模式对 JSON 值中的转义字符的影响的更多信息, 请参阅 JSON_UNQUOTE() 函数描述 。

5.2、JSON 值的规范化、合并和自动包装

5.2.1、规范化 JSON 值

当一个字符串被解析并发现是一个有效的 JSON 文档时,它也会被规范化:具有与文档中先前找到的键重复的键的成员被丢弃(即使值不同)。以下 JSON_OBJECT()调用生成的对象值不包括第二个key1元素,因为该键名出现在值的前面:

mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def');
+------------------------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def') |
+------------------------------------------------------+
| {
   
   "key1": 1, "key2": "abc"}                           |
+------------------------------------------------------+

注意

这种对重复键的“第一键胜出”处理与RFC 7159不一致 。这是 MySQL 5.7 中的一个已知问题,在 MySQL 8.0 中已修复。(错误 #86866,错误 #26369555)

MySQL 还会丢弃原始 JSON 文档中键、值或元素之间的额外空格,并在显示时在每个逗号 ( ,) 或冒号 ( :) 后留下(或在必要时插入)一个空格。这样做是为了提高可读性。

产生 JSON 值的 MySQL 函数(参见 第 12.18.2 节,“创建 JSON 值的函数”)总是返回规范化的值。

为了提高查找效率,它还对 JSON 对象的键进行排序。您应该知道,此排序的结果可能会发生变化,并且不能保证在不同版本中保持一致

5.2.2、合并 JSON 值

在组合多个数组的上下文中,通过将后面命名的数组连接到第一个数组的末尾,将多个数组合并为一个数组。在以下示例中, JSON_MERGE() 将其参数合并到一个数组中:

mysql> SELECT JSON_MERGE('[1, 2]', '["a", "b"]', '[true, false]');
+-----------------------------------------------------+
| JSON_MERGE('[1, 2]', '["a", "b"]', '[true, false]') |
+-----------------------------------------------------+
| [1, 2, "a", "b", true, false]                       |
+-----------------------------------------------------+

将值插入 JSON 列时也会执行合并,如下所示:

mysql> CREATE TABLE t1 (c1 JSON);

mysql> INSERT INTO t1 VALUES
     >     ('{"x": 17, "x": "red"}'),
     >     ('{"x": 17, "x": "red", "x": [3, 5, 7]}');

mysql> SELECT c1 FROM t1;
+-----------+
| c1        |
+-----------+
| {
   
   "x": 17} |
| {
   
   "x": 17} |
+-----------+

多个对象合并时产生一个对象。如果多个对象具有相同的键,则生成的合并对象中该键的值是包含键值的数组:

mysql> SELECT JSON_MERGE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}');
+----------------------------------------------------+
| JSON_MERGE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}') |
+----------------------------------------------------+
| {
   
   "a": [1, 4], "b": 2, "c": 3}                      |
+----------------------------------------------------+

5.2.3、自动包装 JSON 值

  • 非数组值自动包装

在需要数组值的上下文中使用的非数组值是自动包装的:该值由[]字符包围,以将其转换为数组。在以下语句中,每个参数都自动包装为数组 ( [1], [2])。然后将它们合并以生成单个结果数组:

mysql> SELECT JSON_MERGE('1', '2'); # -> 临时状态: JSON_MERGE([1], [2])
+----------------------+
| JSON_MERGE('1', '2') |
+----------------------+
| [1, 2]               |
+----------------------+
  • 对象自动包装

通过将对象自动包装为数组并合并两个数组来合并数组和对象值:

mysql> SELECT JSON_MERGE('[10, 20]', '{"a": "x", "b": "y"}');
# -> 临时状态:JSON_MERGE('[10, 20]', '[{"a": "x", "b": "y"}]'); 将后面的{} 自动包装为[{}]
+------------------------------------------------+
| JSON_MERGE('[10, 20]', '{"a": "x", "b": "y"}') |
+------------------------------------------------+
| [10, 20, {
   
   "a": "x", "b": "y"}]                 |
+------------------------------------------------+

5.3、搜索和修改 JSON 值

JSON 路径表达式在 JSON 文档中选择一个值。

路径表达式对于提取部分 JSON 文档或修改 JSON 文档的函数很有用,以指定在该文档中的哪个位置进行操作。例如,以下查询从 JSON 文档中提取具有 name键的成员的值:

mysql> SELECT JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name');
+---------------------------------------------------------+
| JSON_EXTRACT('{"id": 14, "name": "Aztalan"}', '$.name') |
+---------------------------------------------------------+
| "Aztalan"                                               |
+---------------------------------------------------------+

路径语法使用一个前导$字符来表示所考虑的 JSON 文档,跟在选择器后面的可选表达式依次指定文档的更具体部分:

  • 后跟键名的句点使用给定键命名对象中的成员。如果不带引号的名称在路径表达式中不合法(例如,它包含空格),则必须在双引号内指定键名称。

  • [N] 紧跟在 path 后表示选择一个数组名(path)的下标为 N 的元素,N 是从零开始的整数。如果选择的 path 不是数组,则*path*[0] 等价于 path

    mysql> SELECT JSON_SET('"x"', '$[0]', 'a');
    +------------------------------+
    | JSON_SET('"x"', '$[0]', 'a') |
    +------------------------------+
    | "a"                          |
    +------------------------------+
    1 row in set (0.00 sec)
    
  • 路径可以包含***通配符:

    • .[*]计算一个 JSON 对象中所有成员的值。
    • [*]计算一个 JSON 数组中所有元素的值。
    • prefix**suffix 计算以 prefix 开头并以 suffix 结尾的所有路径。
  • 文档中不存在的路径(评估为不存在的数据)评估为NULL

$引用这个三个元素的 JSON 数组:

[3, {
    
    "a": [5, 6], "b": 10}, [99, 100]]

然后:

  • $[0]评估为3
  • $[1]评估为{"a": [5, 6], "b": 10}
  • $[2]评估为[99, 100]
  • $[3]计算结果为NULL (它指的是第四个数组元素,它不存在)。

因为$[1]$[2] 计算为非标量值,它们可以用作选择嵌套值的更具体的路径表达式的基础。例子:

  • $[1].a评估为[5, 6]
  • $[1].a[1]评估为 6
  • $[1].b评估为 10
  • $[2][0]评估为 99

如前所述,如果键名在路径表达式中不合法,则必须用引号将键的路径组件引起来。让 $ 引用这个值:

{
    
    "a fish": "shark", "a bird": "sparrow"}

这两个键都包含一个空格,并且必须用引号引起来:

  • $."a fish"评估为 shark
  • $."a bird"评估为 sparrow

使用通配符的路径评估为可以包含多个值的数组:

mysql> SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*');
+---------------------------------------------------------+
| JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.*') |
+---------------------------------------------------------+
| [1, 2, [3, 4, 5]]                                       |
+---------------------------------------------------------+
mysql> SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]'); # 与'$.c' 等价
+------------------------------------------------------------+
| JSON_EXTRACT('{"a": 1, "b": 2, "c": [3, 4, 5]}', '$.c[*]') |
+------------------------------------------------------------+
| [3, 4, 5]                                                  |
+------------------------------------------------------------+

在以下示例中,路径$**.b 计算为多个路径 ($.a.b$.c.b) 并生成匹配路径值的数组:

mysql> SELECT JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b');
+---------------------------------------------------------+
| JSON_EXTRACT('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b') |
+---------------------------------------------------------+
| [1, 2]                                                  |
+---------------------------------------------------------+

在 MySQL 5.7.9 及更高版本中,您可以使用 column->path JSON 列标识符和 JSON 路径表达式作为 JSON_EXTRACT(column, path) 的同义词. 有关更多信息,请参阅 第 12.18.3 节,“搜索 JSON 值的函数”。另请参阅 索引生成的列以提供 JSON 列索引

一些函数采用现有的 JSON 文档,以某种方式对其进行修改,然后返回修改后的文档作为结果。路径表达式指示在文档中进行更改的位置。例如,JSON_SET()JSON_INSERT()JSON_REPLACE()函数各自接受一个 JSON 文档,加上一个或多个路径/值对,这些“对”描述在哪里修改文档和要使用的值。这些函数在处理文档中现有值和不存在值的方式上有所不同。

考虑这个文件:

mysql> SET @j = '["a", {"b": [true, false]}, [10, 20]]';

JSON_SET()替换存在的路径的值并添加不存在的路径的值:

mysql> SELECT JSON_SET(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+--------------------------------------------+
| JSON_SET(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+--------------------------------------------+
| ["a", {
   
   "b": [1, false]}, [10, 20, 2]]      |
+--------------------------------------------+

在这种情况下,路径$[1].b[0]选择一个现有值 ( true),该值将替换为后面的路径参数值 ( 1) 。该路径$[2][2]不存在,因此将相应的值 ( 2) 添加到 $[2] 选择的值中。

JSON_INSERT()添加新值但不替换现有值:

mysql> SELECT JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+-----------------------------------------------+
| JSON_INSERT(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+-----------------------------------------------+
| ["a", {
   
   "b": [true, false]}, [10, 20, 2]]      |
+-----------------------------------------------+
# TODO: 没看明白,为什么 '$[1].b[0]', 1 这个路径/值 对没有被添加到"b"数组的0号下标中

JSON_REPLACE()替换现有值并忽略新值:

mysql> SELECT JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2);
+------------------------------------------------+
| JSON_REPLACE(@j, '$[1].b[0]', 1, '$[2][2]', 2) |
+------------------------------------------------+
| ["a", {
   
   "b": [1, false]}, [10, 20]]             |
+------------------------------------------------+

路径/值对从左到右进行评估。通过评估一对生成的文档成为评估下一对的新值。

JSON_REMOVE()接受一个 JSON 文档和一个(或多个)路径,这些路径指定要从文档中删除的值。返回值是原始文档减去文档中存在的路径选择的值:

mysql> SELECT JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]');
+---------------------------------------------------+
| JSON_REMOVE(@j, '$[2]', '$[1].b[1]', '$[1].b[1]') |
+---------------------------------------------------+
| ["a", {
   
   "b": [true]}]                              |
+---------------------------------------------------+

路径具有以下效果:

  • $[2]匹配[10, 20] 并删除它。
  • 第一个 $[1].b[1]匹配 b 元素中的 false 并将其删除。
  • 第二个 $[1].b[1] 不匹配任何元素:期望匹配的元素已被删除,路径不再存在,并且没有效果。

5.4、JSON 路径语法

MySQL 支持并在本手册其他地方描述的许多 JSON 函数(请参阅第 12.18 节,“JSON 函数”)需要路径表达式来标识 JSON 文档中的特定元素。路径由路径的范围和一个或多个路径分支组成。对于 MySQL JSON 函数中使用的路径,范围始终是正在搜索或以其他方式操作的文档,由前导 $字符表示。路径分支(路径腿)由句点字符 ( .) 分隔。数组中的单元格由 [N] 表示 ,其中 N 是一个非负整数。键名必须是双引号字符串或有效的 ECMAScript 标识符(请参阅 http://www.ecma-international.org/ecma-262/5.1/#sec-7.6)。路径表达式(如 JSON 文本)应使用 asciiutf8utf8mb4字符集进行编码。其他字符编码被隐式强制转换为utf8mb4. 完整的语法如下所示:

pathExpression:
    scope[(pathLeg)*]

pathLeg:
    member | arrayLocation | doubleAsterisk

member:
    period ( keyName | asterisk )

arrayLocation:
    leftBracket ( nonNegativeInteger | asterisk ) rightBracket

keyName:
    ESIdentifier | doubleQuotedString

doubleAsterisk:
    '**'

period:
    '.'

asterisk:
    '*'

leftBracket:
    '['

rightBracket:
    ']'

如前所述,在 MySQL 中,路径的范围始终是正在操作的文档,表示为 $. 您可以'$'在 JSON 路径表达式中用作文档的同义词。

笔记

一些实现支持 JSON 路径范围的列引用;目前,MySQL 不支持这些。

通配符*** 标记的使用如下:

  • .*表示对象中所有成员的值。

  • [*]表示数组中所有单元格的值。

  • [prefix]**suffix 表示以 prefix 开头和 suffix 结尾的所有路径。 prefix 是可选的,但 suffix 是必需的;换句话说,路径不可能以 ** 结尾。

    此外,路径可能不包含序列 *** (3个星号)。

有关路径语法示例,请参阅将路径作为参数的各种 JSON 函数的描述,例如 JSON_CONTAINS_PATH()JSON_SET()JSON_REPLACE()。有关使用 * ** 通配符的示例,请参阅 JSON_SEARCH()函数说明。

5.5、JSON值的比较和排序

可以使用 =<<=>>=<>!=<=> 运算符 比较 JSON 值。

JSON 值尚不支持以下比较运算符和函数:

刚刚列出的比较运算符和函数的解决方法是将 JSON 值转换为原生 MySQL 数字或字符串数据类型,以便它们具有一致的非 JSON 标量类型。

JSON 值的比较发生在两个级别。第一级比较基于比较值的 JSON 类型。如果类型不同,则比较结果仅取决于哪种类型具有更高的优先级。如果两个值具有相同的 JSON 类型,则使用特定于类型的规则进行第二级比较。

以下列表显示了 JSON 类型的优先级,从最高优先级到最低优先级。(类型名称是JSON_TYPE() 函数返回的名称。)一起显示在一行中的类型具有相同的优先级。列表中前面列出的 JSON 类型的任何值都比列表后面列出的 JSON 类型的任何值都大。

BLOB
BIT
OPAQUE
DATETIME
TIME
DATE
BOOLEAN
ARRAY
OBJECT
STRING
INTEGER, DOUBLE
NULL

对于相同优先级的 JSON 值,比较规则是特定于类型的:

  • BLOB

    比较两个值的前 N 个字节,其中 N 是较短值中的字节数。如果两个值的前 N 个字节相同,则较短的值在较长的值之前排序。

  • BIT

    BLOB 相同的规则。

  • OPAQUE

    BLOB 相同的规则。 OPAQUE 类型是未被分类的类型。

  • DATETIME

    较早时间点的值排在表示较晚时间点的值之前。如果两个值最初分别来自 MySQL DATETIMETIMESTAMP 类型,如果它们代表相同的时间点,则它们是相等的。

  • TIME

    两个时间值中较小的一个排在较大的之前。

  • DATE

    较早的日期在较晚的日期之前排序。

  • ARRAY

    如果两个 JSON 数组具有相同的长度并且在数组中对应位置的值相等,则它们是相等的。

    如果数组不相等,则它们的顺序由第一个存在差异所在位置的元素确定。在该位置具有较小值的数组排在前面。如果较短数组的所有值都等于较长数组中的相应值,则较短数组首先排序。

    例子:

    [] < ["a"] < ["ab"] < ["ab", "cd", "ef"] < ["ab", "ef"]
    
  • BOOLEAN

    JSON 的 false 字符小于 JSON 的 true 字符。

  • OBJECT

    如果两个 JSON 对象具有相同的一组键,并且每个键在两个对象中具有相同的值,则它们是相等的。

    例子:

    {"a": 1, "b": 2} = {"b": 2, "a": 1}
    

    两个不相等的对象的顺序是未指定的,但具有确定性。(注:未明白这句话)

  • STRING

    字符串在被比较的两个字符串以 utf8mb4 编码表示的前 N 字节上按词法排序 ,其中 N 是较短字符串的长度。如果两个字符串的前 N 个字节相同,则认为较短的字符串小于较长的字符串。

    例子:

    "a" < "ab" < "b" < "bc"
    

    此排序等同于使用 utf8mb4_bin collation 对 SQL 字符串进行排序。因为 utf8mb4_bin是二进制排序规则,所以 JSON 值的比较区分大小写:

    "A" < "a"
    
  • INTEGER, DOUBLE

    JSON 值可以包含精确值数字和近似值数字。有关这些类型数字的一般讨论,请参阅第 9.1.2 节,“数字文字”

    比较原生 MySQL 数值类型的规则在第 12.3 节,“表达式求值中的类型转换”中讨论,但是比较 JSON 值中的数值的规则有些不同:

    • 在分别使用原生 MySQL INTDOUBLE 数字类型的两列之间的比较中,已知所有比较都涉及整数和双精度数,因此对于所有行,整数都转换为双精度数。即,将精确值数转换为近似值数。

    • 另一方面,如果查询比较两个包含数字的 JSON 列,则无法预先知道数字是整数还是双精度数。为了在所有行中提供最一致的行为,MySQL 将近似值数字转换为精确值数字。结果排序是一致的,并且不会丢失精确值数字的精度。例如,给定标量 9223372036854775805、9223372036854775806、9223372036854775807 和 9.223372036854776e18,顺序如下:

    9223372036854775805 < 9223372036854775806 < 9223372036854775807
    < 9.223372036854776e18 = 9223372036854776000 < 9223372036854776001
    

    如果 JSON 比较使用非 JSON 数字比较规则,可能会出现不一致的排序。常见的 MySQL 数字比较规则产生以下顺序:

    • 整数比较:

      9223372036854775805 < 9223372036854775806 < 9223372036854775807
      

      (未定义 9.223372036854776e18)

    • 双重比较:

      9223372036854775805 = 9223372036854775806 = 9223372036854775807 = 9.223372036854776e18
      

对于任何 JSON 值与 SQLNULL的比较,结果是UNKNOWN.

对于 JSON 和非 JSON 值的比较,非 JSON 值根据下表中的规则转换为 JSON,然后按前面所述进行值比较。

5.6、在 JSON 和非 JSON 值之间转换

下表总结了 MySQL 在 JSON 值和其他类型的值之间进行转换时遵循的规则:

表 11.3 JSON 转换规则

其他类型 CAST(其他类型 AS JSON) CAST(JSON AS 其他类型)
JSON 没变 没变
utf8 字符类型 ( utf8mb4, utf8, ascii) 该字符串被解析为 JSON 值。 JSON 值被序列化为utf8mb4字符串。
其他字符类型 其他字符编码被隐式转换 为 utf8mb4 字符类型并按照 utf8 字符集处理。 JSON 值被序列化为utf8mb4字符串,然后转换为其他字符编码。结果可能没有意义。
NULL 返回 NULL 的 JSON 类型的值。 不适用。
GEO类型 通过调用 ST_AsGeoJSON() 将GEO值转换为 JSON 文档。 非法操作。解决方法:将 CAST(json_val AS CHAR) 的结果传递给 ST_GeomFromGeoJSON() 的结果传递给 ST_GeomFromGeoJSON()
所有其他类型 生成由单个标量值组成的 JSON 文档。 如果 JSON 文档包含目标类型的单个标量值并且该标量值可以转换为目标类型,则成功。否则,返回 NULL 并产生警告。

对于 JSON 值的 ORDER BYGROUP BY 根据以下原则工作:

  • 标量 JSON 值的排序使用与前面讨论中相同的规则。
  • 对于升序排序,SQL的 NULL 排在所有 JSON 值之前,包括 JSON NULL字面量;对于降序排序,SQL 的 NULL 排在所有 JSON 值进行之后,包括 JSON NULL字面量。
  • JSON 值的排序键受 max_sort_length系统变量值的约束,因此如果前 max_sort_length 个字节相同(之后才有差异),则认为相等。
  • 当前不支持对非标量值进行排序,并且会出现警告。

对于排序,将 JSON 标量转换为其他一些本机 MySQL 类型可能是有益的。例如,如果名为 jdoc 的列包含 JSON 对象,其成员由id键和非负值组成,请使用此表达式按id 值排序:

ORDER BY CAST(JSON_EXTRACT(jdoc, '$.id') AS UNSIGNED)

如果碰巧有一个生成的列定义为使用与 ORDER BY 中相同的表达式,MySQL 优化器会识别出这一点并考虑将索引用于查询执行计划。请参阅 第 8.3.10 节,“优化器使用生成的列索引”

5.7、JSON 值的聚合

对于 JSON 值的聚合,SQL NULL 值与其他数据类型一样被忽略。非 NULL 值转换为数值(numeric)类型并进行聚合,除了 MIN()MAX()GROUP_CONCAT()。对于数字标量的 JSON 值,转换为数字应该会产生有意义的结果,尽管(取决于值)可能会发生截断和精度损失。将其他 JSON 值转换为数字(number)可能不会产生有意义的结果。

5.8、相关参考:

第 8.3.10 节,“优化器使用生成的列索引”

第 9.1.2 节,“数字文字”

第 11.7 节,“数据类型存储要求”

第 12.3 节,“表达式求值中的类型转换”

第 12.17.11 节,“空间 GeoJSON 函数”

第 12.18 节,“JSON 函数”

第 12.18.2 节,“创建 JSON 值的函数”

第 12.18.3 节,“搜索 JSON 值的函数”

第 13.1.18.8节,索引生成的列以提供 JSON 列索引

6、数据类型默认值

7、数据类型存储要求

7.1、 InnoDB 表存储要求

7.2、 NDB 表存储要求

7.3、 数字类型存储要求

7.4、 日期和时间类型存储要求

7.5、 字符串类型存储要求

7.6、 空间类型存储要求

7.7、 JSON 存储要求

7.8、相关参考

磁盘上表数据的存储要求取决于几个因素。不同的存储引擎表示数据类型和存储原始数据的方式不同。表数据可能会针对一列或整行进行压缩,从而使表或列的存储要求的计算变得复杂。

尽管磁盘上的存储布局存在差异,但用于通信和交换有关表行信息的内部 MySQL API 使用适用于所有存储引擎的一致数据结构。

本节包括 MySQL 支持的每种数据类型的存储要求的指南和信息,包括使用固定大小表示的数据类型的存储引擎的内部格式和大小。信息按类别或存储引擎列出。

表的内部表示最大行大小为 65,535 字节,即使存储引擎能够支持更大的行。此数字不包括 BLOBTEXT列,它们仅占此大小的 9 到 12 个字节。对于 BLOBTEXT数据,信息在内部存储在与行缓冲区不同的内存区域中。不同的存储引擎根据它们用于处理相应类型的方法,以不同的方式处理这些数据的分配和存储。有关详细信息,请参阅第 15 章,替代存储引擎第 8.4.7 节,“表列数和行大小的限制”

7.1、 InnoDB 表存储要求

有关 InnoDB 表的存储要求的信息, 请参阅第 14.11 节,“InnoDB 行格式”

7.2、 NDB 表存储要求

(跳过)

7.3、 数字类型存储要求

数据类型 需要存储
TINYINT 1 个字节
SMALLINT 2 个字节
MEDIUMINT 3 个字节
INT, INTEGER 4 个字节
BIGINT 8 个字节
FLOAT(p) 4 个字节( 0 <= p<= 24 ) ,8 个字节( 25 <= p<= 53 )
FLOAT 4 个字节
DOUBLE [PRECISION], REAL 8 个字节
DECIMAL(M,D), NUMERIC(M,D) 变长的; 见以下讨论
BIT(M) 大约 ( M+7)/8 字节

DECIMAL( 和 NUMERIC ) 列的值使用二进制格式表示,该格式将九个十进制(以 10 为基数)数字打包成四个字节。每个值的整数和小数部分的存储分别确定。每个九位数字的倍数需要四个字节,而“剩余” 数字需要四个字节的一部分。下表给出了多余数字所需的存储空间。

剩余数字 字节数
0 0
1, 2 1
3, 4 2
5, 6 3
7, 8 4

7.4、 日期和时间类型存储要求

对于TIMEDATETIMETIMESTAMP列,在 MySQL 5.6.4 之前创建的表所需的存储空间与从 5.6.4 开始创建的表不同。这是由于 5.6.4 中的更改允许这些类型具有小数部分,这需要 0 到 3 个字节。

数据类型 MySQL 5.6.4 之前需要存储 MySQL 5.6.4 所需的存储空间
YEAR 1 个字节 1 个字节
DATE 3 个字节 3 个字节
TIME 3 个字节 3 字节 + 小数秒存储
DATETIME 8 个字节 5 字节 + 小数秒存储
TIMESTAMP 4字节 4 字节 + 小数秒存储

从 MySQL 5.6.4 开始,存储 YEARDATE保持不变。但是, TIMEDATETIMETIMESTAMP的表示方式不同。DATETIME打包的效率更高,非小数部分需要 5 个而不是 8 个字节,并且所有3种表示时间的类型的小数部分只需要 0 到 3 个字节,具体取决于存储值的小数秒精度。

小数秒精度 需要存储
0 0 字节
1, 2 1 个字节
3, 4 2 个字节
5, 6 3 个字节

例如,TIME(0)TIME(2)TIME(4)TIME(6)分别使用 3(3+0)、4(3+1)、5(3+2) 和 6(3+3) 个字节。TIMETIME(0)是等效的并且需要相同的存储空间。

有关时间值的内部表示的详细信息,请参阅 MySQL 内部:重要的算法和结构

7.5、 字符串类型存储要求

在下表中,*M*表示非二进制字符串类型的声明列长度(字符长度)和二进制字符串类型的字节数。 *L*表示给定字符串值以字节为单位的实际长度(字节长度)。

数据类型 需要存储
CHAR(M) 紧凑的 InnoDB 行格式系列优化了可变长度字符集的存储。请参阅 COMPACT 行格式存储特性 。否则,M × w 字节 <= M <= 255,其中 w 是字符集中最大长度字符所需的字节数。
BINARY(M) *M*字节,0 <= M <= 255
VARCHAR(M), VARBINARY(M) L+1 个字节(如果列值需要 0 - 255 个字节),L+2 个字节(如果列值超过 255 个字节)
TINYBLOB, TINYTEXT L+ 1 个字节,其中 L< 2[^8] = 256 B
BLOB, TEXT L+ 2 个字节,其中 L< 2[^16] = 64 KB
MEDIUMBLOB, MEDIUMTEXT L+ 3 个字节,其中 L< 2[^24] = 16 MB
LONGBLOB, LONGTEXT L+ 4 个字节,其中 L< 2[^32] = 4 GB
ENUM('value1','value2',...) 1 或 2 个字节,取决于枚举值的数量(最多 65,535 个值)
SET('value1','value2',...) 1、2、3、4 或 8 个字节,取决于集合成员的数量(最多 64 个成员)

可变长度字符串类型使用长度前缀加数据存储。长度前缀根据数据类型需要一到四个字节,数据值需要 L(字符串的字节长度)。例如,一个 MEDIUMTEXT值的存储需要 *L*字节来存储值加上三个字节来存储值的长度。

要计算用于存储特定 CHARVARCHARTEXT列值的字节数,您必须考虑用于该列的字符集以及该值是否包含多字节字符。特别是,在使用 utf8 Unicode 字符集时,您必须牢记并非所有字符都使用相同的字节数。utf8mb3utf8mb4 字符集每个字符最多分别需要三个和四个字节。有关用于不同类别 utf8mb3utf8mb4 字符的存储细分,请参阅 第 10.9 节,“Unicode 支持”

VARCHAR, VARBINARY, BLOBTEXT类型是变长类型。对于它们的每个,存储要求取决于以下因素:

  • 列值的实际长度
  • 列的最大可能长度
  • 列使用的字符集,因为有些字符集包含多字节字符

例如,一个 VARCHAR(255) 列可以包含最大长度为 255 个字符的字符串。假设该列使用latin1字符集(每个字符一个字节),实际需要的存储是字符串的长度(L),加上一个字节来记录字符串的长度。对于字符串 'abcd',*L*是 4 并且存储要求是 5 个字节。如果同一列改为使用ucs2双字节字符集,则存储要求为 10 个字节: 'abcd' 的长度为 8 个字节,该列需要两个字节来存储长度,因为最大长度大于 255(最多 510字节)。

一个 VARCHARVARBINARY 列中可以存储的最大有效字节数取决于最大行大小 65,535 字节,该最大行大小在所有列之间共享。对于存储多字节字符的 VARCHAR 列,最大有效字符数较少。例如, utf8mb3 的每个字符最多需要三个字节,因此可以将使用 utf8mb3 字符集的 VARCHAR 列声明为最多 21,844 个字符。请参阅 第 8.4.7 节,“表列数和行大小的限制”

InnoDB将长度大于或等于 768 字节的固定长度字段编码为可变长度字段,可以在页外存储。例如, CHAR(255)如果字符集的最大字节长度大于 3,则列可以超过 768 个字节,就像utf8mb4

NDB存储引擎支持可变宽度列 。这意味着 VARCHARNDB Cluster 表中的列需要与任何其他存储引擎相同的存储量,除了这些值是 4 字节对齐的。因此,使用字符集 latin1 存储在 VARCHAR(50)列中的 'abcd' 字符串需要 8 个字节(而不是 MyISAM表中相同列值的 5 个字节)。

(此处省略NDB相关的其他描述)NDB_COLUMN有关详细信息,请参阅 NDB_COLUMN 选项

ENUM 对象的大小由不同枚举值的数量决定。一个字节用于最多包含 255 个可能值的枚举。两个字节用于具有 256 到 65,535 个可能值的枚举。请参阅 第 11.3.5 节,“ENUM 类型”

SET 对象的大小由不同集合成员的数量决定。如果设置大小为*N*,则对象占用 (N+7)/8 字节,四舍五入为 1、2、3、4 或 8 个字节。一个 SET 最多可以有 64 个成员。请参阅 第 11.3.6 节,“SET 类型”

7.6、 空间类型存储要求

MySQL 使用 4 个字节存储空间值以指示 SRID,后跟该值的 WKB 表示。该 LENGTH()函数返回值存储所需的空间(以字节为单位)。

有关空间值的 WKB 和内部存储格式的描述,请参阅第 11.4.3 节,“支持的空间数据格式”

7.7、 JSON 存储要求

通常, JSON 列的存储要求与 LONGBLOBLONGTEXT 列的存储要求大致相同;也就是说,JSON 文档占用的空间与存储在其中一种类型的列中的文档字符串表示所占用的空间大致相同。但是,存储在 JSON 文档中的各个值的二进制编码(包括查找所需的元数据和字典)会产生开销。例如,存储在 JSON 文档中的字符串需要 4 到 10 个字节的额外存储空间,具体取决于字符串的长度以及存储它的对象或数组的大小。

此外,MySQL 对存储在JSON列中的任何 JSON 文档的大小施加了限制,使其不能大于 max_allowed_packet.

7.8、相关参考

第 8.4.7 节,“表列数和行大小的限制”

第 10.9 节,“Unicode 支持”

第 11.3.5 节,“ENUM 类型”

第 11.3.6 节,“SET 类型”

第 14.11 节,“InnoDB 行格式”

第 14.11 节,COMPACT 行格式存储特性

第 15 章,替代存储引擎

MySQL 内部:重要的算法和结构

8、为列选择正确的类型

9、使用来自其他数据库引擎的数据类型

猜你喜欢

转载自blog.csdn.net/booynal/article/details/125705927
今日推荐