MySQL8-中文参考-二十-
MySQL8 中文参考(二十)
原文:
dev.mysql.com/doc/refman/8.0/en/collation-diagnostics.html
12.14.4.3 Index.xml 解析期间的诊断
MySQL 服务器在解析Index.xml
文件时发现问题时会生成诊断信息:
-
未知标记会被写入错误日志。例如,如果排序规则定义包含
<aaa>
标记,则会产生以下消息:[Warning] Buffered warning: Unknown LDML tag: 'charsets/charset/collation/rules/aaa'
-
如果排序规则初始化不可能,服务器会报告“未知排序规则”错误,并生成解释问题的警告,就像前面的例子一样。在其他情况下,如果排序规则描述通常正确但包含一些未知标记,排序规则会被初始化并可供使用。未知部分会被忽略,但错误日志中会生成警告。
-
排序规则存在问题会生成警告,客户端可以使用
SHOW WARNINGS
显示这些警告。假设重置规则包含一个长度超过 6 个字符的扩展:<reset>abcdefghi</reset> <i>x</i>
尝试使用排序规则会产生警告:
mysql> SELECT _utf8mb4'test' COLLATE utf8mb4_test_ci; ERROR 1273 (HY000): Unknown collation: 'utf8mb4_test_ci' mysql> SHOW WARNINGS; +---------+------+----------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------+ | Error | 1273 | Unknown collation: 'utf8mb4_test_ci' | | Warning | 1273 | Expansion is too long at 'abcdefghi=x' | +---------+------+----------------------------------------+
12.15 字符集配置
原文:
dev.mysql.com/doc/refman/8.0/en/charset-configuration.html
MySQL 服务器具有编译默认字符集和排序规则。要更改这些默认值,请在启动服务器时使用--character-set-server
和--collation-server
选项。请参阅第 7.1.7 节,“服务器命令选项”。排序规则必须是默认字符集的合法排序规则。要确定每个字符集可用的排序规则,请使用SHOW COLLATION
语句或查询INFORMATION_SCHEMA
COLLATIONS
表。
如果您尝试使用未编译到二进制文件中的字符集,可能会遇到以下问题:
-
如果您的程序使用不正确的路径来确定字符集存储的位置(通常是 MySQL 安装目录下的
share/mysql/charsets
或share/charsets
目录),可以通过在运行程序时使用--character-sets-dir
选项来解决。例如,要指定一个目录供 MySQL 客户端程序使用,请在您的选项文件的[client]
组中列出它。这里给出的示例显示了在 Unix 或 Windows 中分别设置可能是什么样子的:[client] character-sets-dir=/usr/local/mysql/share/mysql/charsets [client] character-sets-dir="C:/Program Files/MySQL/MySQL Server 8.0/share/charsets"
-
如果字符集是一个无法动态加载的复杂字符集,您必须重新编译程序以支持该字符集。
对于 Unicode 字符集,您可以使用 LDML 表示法定义排序规则,而无需重新编译。请参阅第 12.14.4 节,“向 Unicode 字符集添加 UCA 排序规则”。
-
如果字符集是动态字符集,但您没有配置文件,您应该从新的 MySQL 发行版中安装字符集的配置文件。
-
如果您的字符集索引文件(
Index.xml
)不包含字符集的名称,您的程序将显示错误消息:Character set '*charset_name*' is not a compiled character set and is not specified in the '/usr/share/mysql/charsets/Index.xml' file
要解决这个问题,您应该获取一个新的索引文件或手动将任何缺失的字符集名称添加到当前文件中。
您可以强制客户端程序使用特定的字符集,如下所示:
[client]
default-character-set=*charset_name*
这通常是不必要的。然而,当character_set_system
与character_set_server
或character_set_client
不同时,并且您手动输入字符(作为数据库对象标识符、列值或两者),这些字符可能会在客户端输出中显示不正确,或者输出本身可能格式不正确。在这种情况下,使用--default-character-set=*
system_character_set*
启动 mysql 客户端——即,将客户端字符集设置为与系统字符集匹配——应该可以解决问题。
12.16 MySQL 服务器区域设置支持
由 lc_time_names
系统变量指示的区域控制用于显示日期和月份名称和缩写的语言。 此变量影响 DATE_FORMAT()
、DAYNAME()
和 MONTHNAME()
函数的输出。
lc_time_names
不会影响 STR_TO_DATE()
或 GET_FORMAT()
函数。
lc_time_names
的值不会影响 FORMAT()
的结果,但此函数接受一个可选的第三个参数,该参数允许指定用于结果数字的小数点、千位分隔符和分隔符之间分组的区域设置。 可接受的区域值与 lc_time_names
系统变量的合法值相同。
区域名称由 IANA 列出的语言和地区子标签组成(www.iana.org/assignments/language-subtag-registry
),例如 'ja_JP'
或 'pt_BR'
。 默认值是 'en_US'
,不受系统区域设置影响,但您可以在服务器启动时设置该值,或者在运行时设置 GLOBAL
值(如果您有足够的权限设置全局系统变量);参见 7.1.9.1 系统变量权限。 任何客户端都可以检查 lc_time_names
的值或设置其 SESSION
值以影响自己连接的区域设置。
mysql> SET NAMES 'utf8mb4';
Query OK, 0 rows affected (0.09 sec)
mysql> SELECT @@lc_time_names;
+-----------------+
| @@lc_time_names |
+-----------------+
| en_US |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT DAYNAME('2020-01-01'), MONTHNAME('2020-01-01');
+-----------------------+-------------------------+
| DAYNAME('2020-01-01') | MONTHNAME('2020-01-01') |
+-----------------------+-------------------------+
| Wednesday | January |
+-----------------------+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT DATE_FORMAT('2020-01-01','%W %a %M %b');
+-----------------------------------------+
| DATE_FORMAT('2020-01-01','%W %a %M %b') |
+-----------------------------------------+
| Wednesday Wed January Jan |
+-----------------------------------------+
1 row in set (0.00 sec)
mysql> SET lc_time_names = 'es_MX';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@lc_time_names;
+-----------------+
| @@lc_time_names |
+-----------------+
| es_MX |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT DAYNAME('2020-01-01'), MONTHNAME('2020-01-01');
+-----------------------+-------------------------+
| DAYNAME('2020-01-01') | MONTHNAME('2020-01-01') |
+-----------------------+-------------------------+
| miércoles | enero |
+-----------------------+-------------------------+
1 row in set (0.00 sec)
mysql> SELECT DATE_FORMAT('2020-01-01','%W %a %M %b');
+-----------------------------------------+
| DATE_FORMAT('2020-01-01','%W %a %M %b') |
+-----------------------------------------+
| miércoles mié enero ene |
+-----------------------------------------+
1 row in set (0.00 sec)
受影响函数的每个日期或月份名称都从 utf8mb4
转换为由 character_set_connection
系统变量指示的字符集。
lc_time_names
可设置为以下任一区域值。 MySQL 支持的区域集合可能与操作系统支持的不同。
区域值 | 含义 |
---|---|
ar_AE |
阿拉伯语 - 阿拉伯联合酋长国 |
ar_BH |
阿拉伯语 - 巴林 |
ar_DZ |
阿拉伯语 - 阿尔及利亚 |
ar_EG |
阿拉伯语 - 埃及 |
ar_IN |
阿拉伯语 - 印度 |
ar_IQ |
阿拉伯语 - 伊拉克 |
ar_JO |
阿拉伯语 - 约旦 |
ar_KW |
阿拉伯语 - 科威特 |
ar_LB |
阿拉伯语 - 黎巴嫩 |
ar_LY |
阿拉伯语 - 利比亚 |
ar_MA |
阿拉伯语 - 摩洛哥 |
ar_OM |
阿拉伯语 - 阿曼 |
ar_QA |
阿拉伯语 - 卡塔尔 |
ar_SA |
阿拉伯语 - 沙特阿拉伯 |
ar_SD |
阿拉伯语 - 苏丹 |
ar_SY |
阿拉伯语 - 叙利亚 |
ar_TN |
阿拉伯语 - 突尼斯 |
ar_YE |
阿拉伯语 - 也门 |
be_BY |
白俄罗斯语 - 白俄罗斯 |
bg_BG |
保加利亚语 - 保加利亚 |
ca_ES |
加泰罗尼亚语 - 西班牙 |
cs_CZ |
捷克语 - 捷克共和国 |
da_DK |
丹麦语 - 丹麦 |
de_AT |
德语 - 奥地利 |
de_BE |
德语 - 比利时 |
de_CH |
德语 - 瑞士 |
de_DE |
德语 - 德国 |
de_LU |
德语 - 卢森堡 |
el_GR |
希腊语 - 希腊 |
en_AU |
英语 - 澳大利亚 |
en_CA |
英语 - 加拿大 |
en_GB |
英语 - 英国 |
en_IN |
英语 - 印度 |
en_NZ |
英语 - 新西兰 |
en_PH |
英语 - 菲律宾 |
en_US |
英语 - 美国 |
en_ZA |
英语 - 南非 |
en_ZW |
英语 - 津巴布韦 |
es_AR |
西班牙语 - 阿根廷 |
es_BO |
西班牙语 - 玻利维亚 |
es_CL |
西班牙语 - 智利 |
es_CO |
西班牙语 - 哥伦比亚 |
es_CR |
西班牙语 - 哥斯达黎加 |
es_DO |
西班牙语 - 多米尼加共和国 |
es_EC |
西班牙语 - 厄瓜多尔 |
es_ES |
西班牙语 - 西班牙 |
es_GT |
西班牙语 - 危地马拉 |
es_HN |
西班牙语 - 洪都拉斯 |
es_MX |
西班牙语 - 墨西哥 |
es_NI |
西班牙语 - 尼加拉瓜 |
es_PA |
西班牙语 - 巴拿马 |
es_PE |
西班牙语 - 秘鲁 |
es_PR |
西班牙语 - 波多黎各 |
es_PY |
西班牙语 - 巴拉圭 |
es_SV |
西班牙语 - 萨尔瓦多 |
es_US |
西班牙语 - 美国 |
es_UY |
西班牙语 - 乌拉圭 |
es_VE |
西班牙语 - 委内瑞拉 |
et_EE |
爱沙尼亚语 - 爱沙尼亚 |
eu_ES |
巴斯克语 - 西班牙 |
fi_FI |
芬兰语 - 芬兰 |
fo_FO |
法罗语 - 法罗群岛 |
fr_BE |
法语 - 比利时 |
fr_CA |
法语 - 加拿大 |
fr_CH |
法语 - 瑞士 |
fr_FR |
法语 - 法国 |
fr_LU |
法语 - 卢森堡 |
gl_ES |
加利西亚语 - 西班牙 |
gu_IN |
古吉拉特语 - 印度 |
he_IL |
希伯来语 - 以色列 |
hi_IN |
印地语 - 印度 |
hr_HR |
克罗地亚语 - 克罗地亚 |
hu_HU |
匈牙利语 - 匈牙利 |
id_ID |
印尼语 - 印度尼西亚 |
is_IS |
冰岛语 - 冰岛 |
it_CH |
意大利语 - 瑞士 |
it_IT |
意大利语 - 意大利 |
ja_JP |
日语 - 日本 |
ko_KR |
韩语 - 韩国 |
lt_LT |
立陶宛语 - 立陶宛 |
lv_LV |
拉脱维亚语 - 拉脱维亚 |
mk_MK |
马其顿语 - 北马其顿 |
mn_MN |
蒙古语 - 蒙古 |
ms_MY |
马来语 - 马来西亚 |
nb_NO |
挪威语(书面) - 挪威 |
nl_BE |
荷兰语 - ��利时 |
nl_NL |
荷兰语 - 荷兰 |
no_NO |
挪威语 - 挪威 |
pl_PL |
波兰语 - 波兰 |
pt_BR |
葡萄牙语 - 巴西 |
pt_PT |
葡萄牙语 - 葡萄牙 |
rm_CH |
罗曼什语 - 瑞士 |
ro_RO |
罗马尼亚语 - 罗马尼亚 |
ru_RU |
俄语 - 俄罗斯 |
ru_UA |
俄语 - 乌克兰 |
sk_SK |
斯洛伐克语 - 斯洛伐克 |
sl_SI |
斯洛文尼亚语 - 斯洛文尼亚 |
sq_AL |
阿尔巴尼亚语 - 阿尔巴尼亚 |
sr_RS |
塞尔维亚语 - 塞尔维亚 |
sv_FI |
瑞典语 - 芬兰 |
sv_SE |
瑞典语 - 瑞典 |
ta_IN |
泰米尔语 - 印度 |
te_IN |
泰卢固语 - 印度 |
th_TH |
泰语 - 泰国 |
tr_TR |
土耳其语 - 土耳其 |
uk_UA |
乌克兰语 - 乌克兰 |
ur_PK |
乌尔都语 - 巴基斯坦 |
vi_VN |
越南语 - 越南 |
zh_CN |
中文 - 中国 |
zh_HK |
中文 - 香港 |
zh_TW |
中文 - 台湾 |
Locale Value | 意义 |
第十三章 数据类型
目录
13.1 数值数据类型
13.1.1 数值数据类型语法
13.1.2 整数类型(精确值)- INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT
13.1.3 定点类型(精确值)- DECIMAL, NUMERIC
13.1.4 浮点类型(近似值)- FLOAT, DOUBLE
13.1.5 位值类型 - BIT
13.1.6 数值类型属性
13.1.7 超出范围和溢出处理
13.2 日期和时间数��类型
13.2.1 日期和时间数据类型语法
13.2.2 DATE, DATETIME 和 TIMESTAMP 类型
13.2.3 TIME 类型
13.2.4 YEAR 类型
13.2.5 TIMESTAMP 和 DATETIME 的自动初始化和更新
13.2.6 时间值中的小数秒
13.2.7 MySQL 使用哪种日历?
13.2.8 日期和时间类型之间的转换
13.2.9 日期中的两位年份
13.3 字符串数据类型
13.3.1 字符串数据类型语法
13.3.2 CHAR 和 VARCHAR 类型
13.3.3 BINARY 和 VARBINARY 类型
13.3.4 BLOB 和 TEXT 类型
13.3.5 ENUM 类型
13.3.6 SET 类型
13.4 空间数据类型
13.4.1 空间数据类型
13.4.2 OpenGIS 几何模型
13.4.3 支持的空间数据格式
13.4.4 几何形状的正确性和有效性
13.4.5 空间参考系统支持
13.4.6 创建空间列
13.4.7 填充空间列
13.4.8 获取空间数据
13.4.9 优化空间分析
13.4.10 创建空间索引
13.4.11 使用空间索引
13.5 JSON 数据类型
13.6 数据类型默认值
13.7 数据类型存储要求
13.8 选择列的正确类型
13.9 使用其他数据库引擎的数据类型
MySQL 支持几个类别的 SQL 数据类型:数值类型、日期和时间类型、字符串(字符和字节)类型、空间类型和 JSON
数据类型。本章提供了每个类别中类型属性的概述和更详细的描述,以及数据类型存储需求的摘要。初始概述故意简短。请参阅更详细的描述,了解有关特定数据类型的其他信息,例如您可以指定值的允许格式。
数据类型描述使用以下约定:
-
对于整数类型,
M
表示最大显示宽度。对于浮点和定点类型,M
是可以存储的总位数(精度)。对于字符串类型,M
是最大长度。M
的最大允许值取决于数据类型。 -
D
适用于浮点和定点类型,表示小数点后的位数(精度)。最大可能值为 30,但不应大于M
−2。 -
fsp
适用于TIME
、DATETIME
和TIMESTAMP
类型,表示小数秒精度;即,小数秒部分的小数点后的位数。如果给定fsp
值,则必须在范围 0 到 6 之间。值为 0 表示没有小数部分。如果省略,则默认精度为 0。(这与标准 SQL 默认值 6 不同,以与之前的 MySQL 版本兼容。) -
方括号(
[
和]
)表示类型定义的可选部分。
13.1 数值数据类型
13.1.1 数值数据类型语法
13.1.2 整数类型(精确值) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT
13.1.3 定点类型(精确值) - DECIMAL, NUMERIC
13.1.4 浮点类型(近似值) - FLOAT, DOUBLE
13.1.5 位值类型 - BIT
13.1.6 数值类型属性
13.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
、MEMORY
、InnoDB
和NDB
表。
有关 MySQL 如何处理超出范围值分配给列和在表达式评估期间的溢出的信息,请参阅第 13.1.7 节,“超出范围和溢出处理”。
有关数值数据类型的存储要求的信息,请参阅第 13.7 节,“数据类型存储要求”。
对于操作数值的函数描述,请参阅第 14.6 节,“数值函数和运算符”。对于数值操作数计算结果使用的数据类型取决于操作数的类型和执行的操作。更多信息,请参阅第 14.6.1 节,“算术运算符”。
13.1.1 数字数据类型语法
对于整数数据类型,M
表示最小显示宽度。最大显示宽度为 255。显示宽度与类型可以存储的值范围无关,如 第 13.1.6 节,“数字类型属性” 中所述。
对于浮点和定点数据类型,M
是可以存储的总位数。
截至 MySQL 8.0.17 版本,整数数据类型的显示宽度属性已被弃用;您应该预期在未来的 MySQL 版本中将其移除。
如果为数字列指定了 ZEROFILL
,MySQL 会自动向列添加 UNSIGNED
属性。
截至 MySQL 8.0.17 版本,ZEROFILL
属性对于数字数据类型已被弃用;您应该预期在未来的 MySQL 版本中将其移除。考虑使用其他方法来产生此属性的效果。例如,应用程序可以使用 LPAD()
函数将数字零填充到所需宽度,或者它们可以将格式化的数字存储在 CHAR
列中。
允许 UNSIGNED
属性的数字数据类型也允许 SIGNED
。但是,这些数据类型默认为有符号,因此 SIGNED
属性没有效果。
截至 MySQL 8.0.17 版本,UNSIGNED
属性对于 FLOAT
、DOUBLE
和 DECIMAL
(以及任何同义词)列已被弃用;您应该预期在未来的 MySQL 版本中将其移除。考虑为这些列使用简单的 CHECK
约束代替。
SERIAL
是 BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
的别名。
在整数列的定义中,SERIAL DEFAULT VALUE
是 NOT NULL AUTO_INCREMENT UNIQUE
的别名。
警告
当您在一个类型为 UNSIGNED
的整数值之间进行减法运算时,结果是无符号的,除非启用了 NO_UNSIGNED_SUBTRACTION
SQL 模式。参见 第 14.10 节,“转换函数和运算符”。
-
位值类型。
M
表示每个值的位数,从 1 到 64。如果省略M
,默认值为 1。 -
TINYINT[(*
M*)] [UNSIGNED] [ZEROFILL]
非常小的整数。有符号范围为
-128
到127
。无符号范围为0
到255
。 -
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 | +------------------------+
然而,值
TRUE
和FALSE
仅仅是1
和0
的别名,如下所示: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
既不等于1
也不等于0
。 -
SMALLINT[(*
M*)] [UNSIGNED] [ZEROFILL]
一个小整数。有符号范围是
-32768
到32767
。无符号范围是0
到65535
。 -
MEDIUMINT[(*
M*)] [UNSIGNED] [ZEROFILL]
一个中等大小的整数。有符号范围是
-8388608
到8388607
。无符号范围是0
到16777215
。 -
INT[(*
M*)] [UNSIGNED] [ZEROFILL]
一个正常大小的整数。有符号范围是
-2147483648
到2147483647
。无符号范围是0
到4294967295
。 -
INTEGER[(*
M*)] [UNSIGNED] [ZEROFILL]
这种类型是
INT
的同义词。 -
BIGINT[(*
M*)] [UNSIGNED] [ZEROFILL]
一个大整数。有符号范围是
-9223372036854775808
到9223372036854775807
。无符号范围是0
到18446744073709551615
。SERIAL
是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
的别名。关于
BIGINT
列,有一些需要注意的事项:-
所有算术运算都是使用有符号的
BIGINT
或DOUBLE
值进行的,因此除了使用位函数外,不应使用大于9223372036854775807
(63 位)的无符号大整数!如果这样做,由于将BIGINT
值转换为DOUBLE
时的四舍五入误差,结果中的一些最后几位可能是错误的。MySQL 可以在以下情况下处理
BIGINT
:-
当使用整数来存储大无符号值在
BIGINT
列中。 -
在
MIN(*
col_name*)
或MAX(*
col_name*)
中,其中col_name
指的是BIGINT
列。 -
当使用操作符(
+
、-
、*
等)其中两个操作数都是整数时。
-
-
您始终可以通过使用字符串将精确整数值存储在
BIGINT
列中来存储它。在这种情况下,MySQL 执行一个涉及没有中间双精度表示的字符串到数字的转换。 -
当两个操作数都是整数值时,
-
、+
和*
运算符使用BIGINT
算术。这意味着如果您将两个大整数相乘(或从返回整数的函数得到的结果),当结果大于9223372036854775807
时,您可能会得到意外的结果。
-
-
DECIMAL[(*
M*[,*
D*])] [UNSIGNED] [ZEROFILL]
一种紧凑的“精确”固定点数。
M
是总位数(精度),D
是小数点后的位数(比例)。小数点和(对于负数)-
符号不计入M
。如果D
为 0,则值没有小数点或小数部分。DECIMAL
的最大数字(M
)为 65。支持的小数位数(D
)的最大值为 30。如果省略D
,默认值为 0。如果省略M
,默认值为 10。(DECIMAL
文本的长度也有限制;请参阅第 14.24.3 节,“表达式处理”。)如果指定了
UNSIGNED
,则不允许负值。截至 MySQL 8.0.17,对于DECIMAL
(以及任何同义词)列,UNSIGNED
属性已被弃用;您应该期望在将来的 MySQL 版本中删除对其的支持。考虑为这些列使用简单的CHECK
约束。所有对
DECIMAL
列的基本计算(+
,-
,*
,/
)都以 65 位数字的精度进行。 -
DEC[(*
M*[,*
D*])] [UNSIGNED] [ZEROFILL]
,NUMERIC[(*
M*[,*
D*])] [UNSIGNED] [ZEROFILL]
,FIXED[(*
M*[,*
D*])] [UNSIGNED] [ZEROFILL]
这些类型是
DECIMAL
的同义词。FIXED
同义词可用于与其他数据库系统的兼容性。 -
FLOAT[(*
M*,*
D*)] [UNSIGNED] [ZEROFILL]
一个小(单精度)浮点数。允许的值为
-3.402823466E+38
到-1.175494351E-38
,0
,和1.175494351E-38
到3.402823466E+38
。这些是基于 IEEE 标准的理论极限。实际范围可能会略小,取决于您的硬件或操作系统。M
是总位数,D
是小数点后的位数。如果省略M
和D
,则值将存储到硬件允许的极限。单精度浮点数精确到大约 7 位小数。FLOAT(*M*,*D*)
是一个非标准的 MySQL 扩展。截至 MySQL 8.0.17 版本,此语法已被弃用,您应该期待在未来的 MySQL 版本中移除对其的支持。UNSIGNED
,如果指定,将禁止负值。截至 MySQL 8.0.17 版本,对于FLOAT
类型的列,UNSIGNED
属性已被弃用(以及任何同义词),您应该期待在未来的 MySQL 版本中移除对其的支持。考虑为这些列使用简单的CHECK
约束。在 MySQL 中,所有计算都是以双精度进行的,因此使用
FLOAT
可能会导致一些意外的问题。参见第 B.3.4.7 节,“解决没有匹配行的问题”。 -
FLOAT(*p*) [UNSIGNED] [ZEROFILL]
一个浮点数。p表示位数精度,但 MySQL 仅使用此值来确定是否使用
FLOAT
或DOUBLE
作为结果数据类型。如果p从 0 到 24,数据类型变为没有M或D值的FLOAT
。如果p从 25 到 53,数据类型变为没有M或D值的DOUBLE
。结果列的范围与本节前面描述的单精度FLOAT
或双精度DOUBLE
数据类型的范围相同。UNSIGNED
,如果指定,将禁止负值。截至 MySQL 8.0.17 版本,对于FLOAT
类型的列,UNSIGNED
属性已被弃用(以及任何同义词),您应该期待在未来的 MySQL 版本中移除对其的支持。考虑为这些列使用简单的CHECK
约束。FLOAT(*p*)
语法是为了 ODBC 兼容性而提供的。 -
DOUBLE[(*M*,*D*)] [UNSIGNED] [ZEROFILL]
一个正常大小(双精度)的浮点数。允许的值为
-1.7976931348623157E+308
到-2.2250738585072014E-308
,0
,以及2.2250738585072014E-308
到1.7976931348623157E+308
。这些是基于 IEEE 标准的理论极限。实际范围可能会略小,取决于您的硬件或操作系统。M
是总位数,D
是小数点后的位数。如果省略了M
和D
,则值将存储到硬件允许的极限。双精度浮点数精确到大约 15 位小数。DOUBLE(*
M*,*
D*)
是 MySQL 的非标准扩展。截至 MySQL 8.0.17 版本,此语法已被弃用,您应该期待在未来的 MySQL 版本中移除对其的支持。UNSIGNED
,如果指定,将不允许负值。截至 MySQL 8.0.17 版本,对于DOUBLE
类型的列,UNSIGNED
属性已被弃用(以及任何同义词),您应该期待在未来的 MySQL 版本中移除对其的支持。考虑为这些列使用简单的CHECK
约束。 -
DOUBLE PRECISION[(*
M*,*
D*)] [UNSIGNED] [ZEROFILL]
,REAL[(*
M*,*
D*)] [UNSIGNED] [ZEROFILL]
这些类型是
DOUBLE
的同义词。例外:如果启用了REAL_AS_FLOAT
SQL 模式,则REAL
是FLOAT
的同义词,而不是DOUBLE
。
13.1.2 整数类型(精确值)- INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT
MySQL 支持 SQL 标准整数类型INTEGER
(或INT
)和SMALLINT
。作为对标准的扩展,MySQL 还支持整数类型TINYINT
、MEDIUMINT
和BIGINT
。以下表格显示了每种整数类型所需的存储空间和范围。
表 13.1 MySQL 支持的整数类型所需的存储空间和范围
类型 | 存储空间(字节) | 最小有符号值 | 最小无符号值 | 最大有符号值 | 最大无符号值 |
---|---|---|---|---|---|
TINYINT |
1 | -128 |
0 |
127 |
255 |
SMALLINT |
2 | -32768 |
0 |
32767 |
65535 |
MEDIUMINT |
3 | -8388608 |
0 |
8388607 |
16777215 |
INT |
4 | -2147483648 |
0 |
2147483647 |
4294967295 |
BIGINT |
8 | -2⁶³ |
0 |
2⁶³-1 |
2⁶⁴-1 |
13.1.3 固定点类型(精确值)- DECIMAL, NUMERIC
DECIMAL
和NUMERIC
类型存储精确的数值数据。当需要保留精确精度时,例如在货币数据中,使用这些类型。在 MySQL 中,NUMERIC
被实现为DECIMAL
,因此关于DECIMAL
的以下说明同样适用于NUMERIC
。
MySQL 以二进制格式存储DECIMAL
值。请参阅第 14.24 节,“精度数学”。
在DECIMAL
列声明中,通常会指定精度和标度。例如:
salary DECIMAL(5,2)
在这个例子中,5
是精度,2
是标度。精度表示存储值的有效数字的数量,而标度表示小数点后可以存储的数字的数量。
标准 SQL 要求DECIMAL(5,2)
能够存储任何具有五位数字和两位小数的值,因此可以存储在salary
列中的值范围从-999.99
到999.99
。
在标准 SQL 中,语法DECIMAL(*
M*)
等同于DECIMAL(*
M*,0)
。类似地,语法DECIMAL
等同于DECIMAL(*
M*,0)
,其中实现允许决定M
的值。MySQL 支持DECIMAL
语法的这两种变体形式。M
的默认值为 10。
如果标度为 0,则DECIMAL
值不包含小数点或小数部分。
DECIMAL
的最大数字位数为 65,但给定DECIMAL
列的实际范围可以受到给定列的精度或标度的限制。当为这样的列分配一个具有比指定标度允许的更多小数位数的值时,该值将被转换为该标度。(具体行为取决于操作系统,但通常效果是截断为允许的数字位数。)
13.1.4 浮点类型(近似值) - FLOAT, DOUBLE
原文:
dev.mysql.com/doc/refman/8.0/en/floating-point-types.html
FLOAT
和 DOUBLE
类型表示近似数值数据。MySQL 使用四个字节来存储单精度值,使用八个字节来存储双精度值。
对于 FLOAT
,SQL 标准允许在关键字 FLOAT
后面的括号中指定精度(但不是指数范围)的可选规范,即 FLOAT(*
p*)
。MySQL 也支持这种可选精度规范,但在 FLOAT(*
p*)
中的精度值仅用于确定存储大小。精度从 0 到 23 会导致一个 4 字节的单精度 FLOAT
列。精度从 24 到 53 会导致一个 8 字节的双精度 DOUBLE
列。
MySQL 允许非标准的语法:FLOAT(*
M*,*
D*)
或 REAL(*
M*,*
D*)
或 DOUBLE PRECISION(*
M*,*
D*)
。这里,(*
M*,*
D*)
意味着值可以以最多 M
位数字的形式存储,其中 D
位可以在小数点后面。例如,定义为 FLOAT(7,4)
的列显示为 -999.9999
。当存储值时,MySQL 进行四舍五入,因此如果你将 999.00009
插入到 FLOAT(7,4)
列中,近似结果是 999.0001
。
从 MySQL 8.0.17 开始,非标准的 FLOAT(*
M*,*
D*)
和 DOUBLE(*
M*,*
D*)
语法已被弃用,你应该预期在未来的 MySQL 版本中将不再支持它。
因为浮点值是近似值,而不是精确值,试图在比较中将它们视为精确值可能会导致问题。它们也受平台或实现的依赖性影响。更多信息,请参见 Section B.3.4.8, “浮点值的问题”。
为了最大的可移植性,需要存储近似数值数据的代码应该使用 FLOAT
或 DOUBLE PRECISION
,不需要指定精度或数字位数。
13.1.5 比特值类型 - BIT
BIT
数据类型用于存储比特值。BIT(*
M*)
类型可以存储M
位值。M
的取值范围为 1 到 64。
要指定比特值,可以使用b'*
value*'
表示法。value
是用零和一写成的二进制值。例如,b'111'
和b'10000000'
分别表示 7 和 128。参见第 11.1.5 节,“比特值文字”。
如果给一个长度为BIT(*
M*)
的列赋值,而该值长度小于M
位,那么该值将在左侧用零填充。例如,给一个BIT(6)
列赋值为b'101'
,实际上等同于赋值为b'000101'
。
**NDB Cluster. ** 在给定的NDB
表中使用的所有BIT
列的最大组合大小不能超过 4096 位。
13.1.6 数字类型属性
原文:
dev.mysql.com/doc/refman/8.0/en/numeric-type-attributes.html
MySQL 支持一个扩展,可选择在类型的基本关键字后面的括号中指定整数数据类型的显示宽度。例如,INT(4)
指定了一个显示宽度为四位数的 INT
。应用程序可以使用这个可选的显示宽度来显示宽度小于列指定的宽度的整数值,通过左侧用空格填充它们。(也就是说,这个宽度存在于返回结果集的元数据中。是否使用取决于应用程序。)
显示宽度不限制可以存储在列中的值的范围。也不会阻止比列显示宽度更宽的值正确显示。例如,指定为 SMALLINT(3)
的列具有 -32768
到 32767
的通常 SMALLINT
范围,超出三位数允许范围的值将使用超过三位数的完整显示。
当与可选的(非标准的)ZEROFILL
属性一起使用时,默认的空格填充被零替换。例如,对于声明为 INT(4) ZEROFILL
的列,检索到的值为 5
会显示为 0005
。
注意
ZEROFILL
属性在涉及表达式或 UNION
查询的列中被忽略。
如果您在具有 ZEROFILL
属性的整数列中存储大于显示宽度的值,当 MySQL 为一些复杂的连接生成临时表时,可能会遇到问题。在这些情况下,MySQL 假定数据值适合列显示宽度内。
从 MySQL 8.0.17 开始,ZEROFILL
属性对于数字数据类型已被弃用,整数数据类型的显示宽度属性也是如此。您应该期望在未来的 MySQL 版本中删除对整数数据类型的 ZEROFILL
和显示宽度的支持。考虑使用其他方法来产生这些属性的效果。例如,应用程序可以使用 LPAD()
函数将数字零填充到所需的宽度,或者它们可以将格式化的数字存储在 CHAR
列中。
所有整数类型都可以具有可选的(非标准的)UNSIGNED
属性。无符号类型可用于在列中仅允许非负数或在需要列的较大上限数值范围时使用。例如,如果INT
列是UNSIGNED
,则列范围的大小相同,但其端点向上移动,从-2147483648
和2147483647
到0
和4294967295
。
浮点和定点类型也可以是UNSIGNED
。与整数类型一样,此属性防止负值存储在列中。与整数类型不同,列值的上限范围保持不变。从 MySQL 8.0.17 开始,对于FLOAT
、DOUBLE
和DECIMAL
(以及任何同义词)类型的列,UNSIGNED
属性已被弃用,您应该期望在将来的 MySQL 版本中删除对其的支持。考虑为这些列使用简单的CHECK
约束。
如果为数字列指定ZEROFILL
,MySQL 会自动添加UNSIGNED
属性。
整数或浮点数据类型可以具有AUTO_INCREMENT
属性。当您将NULL
值插入到索引的AUTO_INCREMENT
列中时,该列将设置为下一个序列值。通常情况下,这是*
value*+1
,其中value
是当前表中该列的最大值。(AUTO_INCREMENT
序列从1
开始。)
将0
存储到AUTO_INCREMENT
列中与存储NULL
具有相同效果,除非启用了NO_AUTO_VALUE_ON_ZERO
SQL 模式。
插入NULL
以生成AUTO_INCREMENT
值要求该列声明为NOT NULL
。如果列声明为NULL
,插入NULL
将存储一个NULL
。当您将任何其他值插入到AUTO_INCREMENT
列中时,该列将设置为该值,并且序列将被重置,以便下一个自动生成的值从插入的值顺序生成。
不支持为AUTO_INCREMENT
列使用负值。
CHECK
约束不能引用具有AUTO_INCREMENT
属性的列,也不能将AUTO_INCREMENT
属性添加到已用于CHECK
约束的现有列中。
截至 MySQL 8.0.17 版本,对于 FLOAT
和 DOUBLE
列,AUTO_INCREMENT
支持已被弃用;你应该期待在未来的 MySQL 版本中将其移除。考虑从这些列中移除 AUTO_INCREMENT
属性,或将其转换为整数类型。
13.1.7 超出范围和溢出处理
原文:
dev.mysql.com/doc/refman/8.0/en/out-of-range-and-overflow.html
当 MySQL 将一个值存储在数值列中,该值超出了列数据类型的允许范围时,结果取决于当时生效的 SQL 模式:
-
如果启用了严格的 SQL 模式,MySQL 将拒绝超出范围的值并显示错误,插入操作将失败,符合 SQL 标准。
-
如果未启用任何限制模式,MySQL 会将值截断到列数据类型范围的适当端点,并存储结果值。
当将超出范围的值分配给整数列时,MySQL 会存储代表列数据类型范围相应端点的值。
当浮点或定点列被分配一个超出指定(或默认)精度和标度所暗示范围的值时,MySQL 会存储代表该范围端点的值。
假设表 t1
定义如下:
CREATE TABLE t1 (i1 TINYINT, i2 TINYINT UNSIGNED);
当启用严格的 SQL 模式时,会发生超出范围的错误:
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 TABLE
、LOAD DATA
、UPDATE
和多行INSERT
语句。在严格模式下,这些语句将失败,并且根据表是否为事务表和其他因素,某些或全部值将不会被插入或更改。有关详细信息,请参见第 7.1.11 节,“服务器 SQL 模式”。
在数值表达式评估过程中发生溢出会导致错误。例如,最大的有符号BIGINT
- INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, 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
- DECIMAL, NUMERIC") 值的范围比整数大:
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 模式,将会发生错误并且列保持不变。
13.2 日期和时间数据类型
13.2.1 日期和时间数据类型语法
13.2.2 DATE、DATETIME 和 TIMESTAMP 类型
13.2.3 TIME 类型
13.2.4 YEAR 类型
13.2.5 TIMESTAMP 和 DATETIME 的自动初始化和更新
13.2.6 时间值中的小数秒
13.2.7 MySQL 使用的是哪种日历?
13.2.8 日期和时间类型之间的转换
13.2.9 日期中的两位数年份
用于表示时间值的日期和时间数据类型是DATE
、TIME
、DATETIME
、TIMESTAMP
和 YEAR
。每种时间类型都有一系列有效值,以及一个“零”值,当您指定 MySQL 无法表示的无效值时可以使用。TIMESTAMP
和 DATETIME
类型具有特殊的自动更新行为,详见第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”。
有关时间数据类型的存储要求的信息,请参见第 13.7 节,“数据类型存储要求”。
有关操作时间值的函数的描述,请参见第 14.7 节,“日期和时间函数”。
在处理日期和时间类型时,请记住以下一般考虑事项:
-
MySQL 以标准输出格式检索给定日期或时间类型的值,但它尝试解释您提供的各种输入值的格式(例如,当您指定要分配给或与日期或时间类型进行比较的值时)。有关日期和时间类型允许的格式的描述,请参见第 11.1.3 节,“日期和时间文字”。预期您提供有效值。如果您使用其他格式的值,可能会导致不可预测的结果。
-
尽管 MySQL 尝试以几种格式解释值,但日期部分必须始终按年-月-日的顺序给出(例如,
'98-09-04'
),而不是在其他地方通常使用的月-日-年或日-月-年的顺序(例如,'09-04-98'
,'04-09-98'
)。要将其他顺序的字符串转换为年-月-日顺序,可能会有用的是STR_TO_DATE()
函数。 -
包含 2 位年份值的日期是模棱两可的,因为世纪是未知的。MySQL 使用以下规则解释 2 位年份值:
-
范围在
70-99
的年份值变为1970-1999
。 -
范围在
00-69
的年份值变为2000-2069
。
另请参阅第 13.2.9 节,“日期中的 2 位年份”。
-
-
从一个时间类型转换为另一个时间类型的值转换遵循第 13.2.8 节,“日期和时间类型之间的转换”中的规则。
-
如果将日期或时间值用于数字上下文中,MySQL 将自动将其转换为数字,反之亦然。
-
默认情况下,当 MySQL 遇到超出范围或其他类型无效的日期或时间类型的值时,它将该值转换为该类型的“零”值。例外情况是,超出范围的
TIME
值将被剪切到TIME
范围的适当端点。 -
通过将 SQL 模式设置为适当的值,您可以更准确地指定 MySQL 支持的日期类型。(参见第 7.1.11 节,“服务器 SQL 模式”。)您可以通过启用
ALLOW_INVALID_DATES
SQL 模式,使 MySQL 接受某些日期,例如'2009-11-31'
。当您希望将用户指定的“可能错误”的值(例如在 Web 表单中)存储在数据库中以供将来处理时,这将非常有用。在此模式下,MySQL 仅验证月份在 1 到 12 的范围内,日期在 1 到 31 的范围内。 -
MySQL 允许您在
DATE
或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
模式。 -
“Zero”日期或时间值在 Connector/ODBC 中使用时会自动转换为
NULL
,因为 ODBC 无法处理这些值。
以下表格显示了每种类型的“零”值的格式。这些“零”值是特殊的,但您可以使用表中显示的值显式存储或引用它们。您还可以使用更容易写的值'0'
或0
来做到这一点。对于包含日期部分的时间类型(日期
、日期时间
和时间戳
),使用这些值可能会产生警告或错误。具体行为取决于启用的严格和NO_ZERO_DATE
SQL 模式中的哪些;请参阅第 7.1.11 节,“服务器 SQL 模式”。
数据类型 | “零”值 |
---|---|
日期 |
'0000-00-00' |
时间 |
'00:00:00' |
日期时间 |
'0000-00-00 00:00:00' |
时间戳 |
'0000-00-00 00:00:00' |
年份 |
0000 |
13.2.1 日期和时间数据类型语法
原文:
dev.mysql.com/doc/refman/8.0/en/date-and-time-type-syntax.html
用于表示时间值的日期和时间数据类型是 DATE
、TIME
、DATETIME
、TIMESTAMP
和 YEAR
。
对于 DATE
和 DATETIME
范围描述,“支持” 表示虽然较早的值可能有效,但不保证。
MySQL 允许 TIME
、DATETIME
和 TIMESTAMP
值具有微秒(6 位数字)精度的小数秒。要定义包含小数秒部分的列,请使用语法 *
type_name*(*
fsp*)
,其中 type_name
是 TIME
、DATETIME
或 TIMESTAMP
,fsp
是小数秒精度。例如:
CREATE TABLE t1 (t TIME(3), dt DATETIME(6), ts TIMESTAMP(0));
fsp
值(如果提供)必须在 0 到 6 的范围内。值为 0 表示没有小数部分。如果省略,则默认精度为 0。(这与标准 SQL 默认值 6 不同,以保持与之前 MySQL 版本的兼容性。)
表中的任何 TIMESTAMP
或 DATETIME
列都可以具有自动初始化和更新属性;请参阅 第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”。
-
DATE
日期。支持的范围是
'1000-01-01'
到'9999-12-31'
。MySQL 以'*
YYYY-MM-DD*'
格式显示DATE
值,但允许将值分配给DATE
列,使用字符串或数字。 -
日期和时间的组合。支持范围为
'1000-01-01 00:00:00.000000'
到'9999-12-31 23:59:59.499999'
。MySQL 以'*
YYYY-MM-DD hh:mm:ss*[.*
fraction*]'
格式显示DATETIME
值,但允许将值分配给DATETIME
列,使用字符串或数字。可以给出范围从 0 到 6 的可选
fsp
值,以指定小数秒精度。值为 0 表示没有小数部分。如果省略,则默认精度为 0。自动初始化和更新
DATETIME
列到当前日期和时间可以使用DEFAULT
和ON UPDATE
列定义子句来指定,如第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”中所述。 -
时间戳。范围为
'1970-01-01 00:00:01.000000'
UTC 到'2038-01-19 03:14:07.499999'
UTC。TIMESTAMP
值存储为自纪元('1970-01-01 00:00:00'
UTC)以来的秒数。TIMESTAMP
不能表示值'1970-01-01 00:00:00'
,因为那相当于自纪元以来的 0 秒,值 0 保留用于表示'0000-00-00 00:00:00'
,即“零”TIMESTAMP
值。可以给出范围从 0 到 6 的可选
fsp
值,以指定小数秒精度。值为 0 表示没有小数部分。如果省略,则默认精度为 0。服务器处理
TIMESTAMP
定义的方式取决于explicit_defaults_for_timestamp
系统变量的值(参见第 7.1.8 节,“服务器系统变量”)。如果启用
explicit_defaults_for_timestamp
,则不会自动将DEFAULT CURRENT_TIMESTAMP
或ON UPDATE CURRENT_TIMESTAMP
属性分配给任何TIMESTAMP
列。它们必须明确包含在列定义中。此外,任何未明确声明为NOT NULL
的TIMESTAMP
允许NULL
值。如果禁用
explicit_defaults_for_timestamp
,服务器处理TIMESTAMP
如下:除非另有说明,否则表中的第一个
TIMESTAMP
列被定义为在未明确分配值的情况下自动设置为最近修改的日期和时间。这使得TIMESTAMP
对于记录INSERT
或UPDATE
操作的时间戳非常有用。您还可以通过将其分配为NULL
值将任何TIMESTAMP
列设置为当前日期和时间,除非已使用NULL
属性定义允许NULL
值。可以使用
DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
列定义子句指定自动初始化和更新为当前日期和时间。默认情况下,第一个TIMESTAMP
列具有这些属性,如前所述。但是,表中的任何TIMESTAMP
列都可以定义为具有这些属性。 -
一个时间。范围是
'-838:59:59.000000'
到'838:59:59.000000'
。MySQL 以'*
hh:mm:ss*[.*
fraction*]'
格式显示TIME
值,但允许使用字符串或数字将值分配给TIME
列。可以给出范围为 0 到 6 的可选
fsp
值以指定小数秒精度。值为 0 表示没有小数部分。如果省略,则默认精度为 0。 -
以 4 位数字格式表示的年份。MySQL 以
YYYY
格式显示YEAR
值,但允许使用字符串或数字将值分配给YEAR
列。值显示为1901
到2155
,或0000
。有关
YEAR
显示格式和输入值解释的其他信息,请参见第 13.2.4 节,“年份类型”。注意
截至 MySQL 8.0.19,带有显式显示宽度的
YEAR(4)
数据类型已被弃用;您应该期望在未来的 MySQL 版本中删除对其的支持。取而代之,请使用没有显示宽度的YEAR
,其含义相同。MySQL 8.0 不支持旧版本 MySQL 中允许的 2 位数
YEAR(2)
数据类型。有关转换为 4 位数YEAR
的说明,请参见 2-Digit YEAR(2) Limitations and Migrating to 4-Digit YEAR,在 MySQL 5.7 参考手册中。
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*;
13.2.2 日期、日期时间和时间戳类型
DATE
、DATETIME
和TIMESTAMP
类型是相关的。本节描述它们的特征,它们的相似之处以及它们的区别。MySQL 以几种格式识别DATE
、DATETIME
和TIMESTAMP
值,描述在第 11.1.3 节,“日期和时间文字”中。对于DATE
和DATETIME
范围描述,“支持”表示尽管较早的值可能有效,但不能保证。
DATE
类型用于具有日期部分但没有时间部分的值。MySQL 以'*
YYYY-MM-DD*'
格式检索和显示DATE
值。支持的范围是'1000-01-01'
到'9999-12-31'
。
DATETIME
类型用于包含日期和时间部分的值。MySQL 以'*
YYYY-MM-DD hh:mm:ss*'
格式检索和显示DATETIME
值。支持的范围是'1000-01-01 00:00:00'
到'9999-12-31 23:59:59'
。
TIMESTAMP
数据类型用于包含日期和时间部分的值。TIMESTAMP
的范围是'1970-01-01 00:00:01'
UTC 到'2038-01-19 03:14:07'
UTC。
DATETIME
或TIMESTAMP
值可以包含高达微秒(6 位数字)精度的尾随小数秒部分。特别是,插入到DATETIME
或TIMESTAMP
列中的值中的任何小数部分都会被存储而不是丢弃。包含小数部分时,这些值的格式为'*
YYYY-MM-DD hh:mm:ss*[.*
fraction*]'
,DATETIME
值的范围是'1000-01-01 00:00:00.000000'
到'9999-12-31 23:59:59.499999'
,TIMESTAMP
值的范围是'1970-01-01 00:00:01.000000'
到'2038-01-19 03:14:07.499999'
。小数部分应始终用小数点与时间的其余部分分隔;不识别其他小数秒分隔符。有关 MySQL 中对小数秒的支持的信息,请参见第 13.2.6 节,“时间值中的小数秒”。
TIMESTAMP
和DATETIME
数据类型提供自动初始化和更新到当前日期和时间。有关更多信息,请参见第 13.2.5 节,“时间戳和日期时间的自动初始化和更新”。
MySQL 将TIMESTAMP
值从当前时区转换为 UTC 进行存储,然后从 UTC 转换回当前时区进行检索。(对于DATETIME
等其他类型,不会发生这种情况。)默认情况下,每个连接的当前时区是服务器的时区。时区可以根据每个连接设置。只要时区设置保持不变,您将获得与存储的相同值。如果存储了TIMESTAMP
值,然后更改时区并检索该值,则检索到的值与存储的值不同。这是因为在两个方向的转换中没有使用相同的时区。当前时区可作为time_zone
系统变量的值获得。有关更多信息,请参阅第 7.1.15 节,“MySQL 服务器时区支持”。
在 MySQL 8.0.19 及更高版本中,您可以在将TIMESTAMP
或DATETIME
值插入表时指定时区偏移量。有关更多信息和示例,请参阅第 11.1.3 节,“日期和时间文字”。
如果 SQL 模式允许此转换,则无效的DATE
、DATETIME
或TIMESTAMP
值将被转换为相应类型的“零”值('0000-00-00'
或'0000-00-00 00:00:00'
)。具体行为取决于是否启用了严格 SQL 模式和NO_ZERO_DATE
SQL 模式中的哪一个;请参阅第 7.1.11 节,“服务器 SQL 模式”。
在 MySQL 8.0.22 及更高版本中,您可以使用带有AT TIME ZONE
运算符的CAST()
将TIMESTAMP
值转换为 UTCDATETIME
值,如下所示:
mysql> SELECT col,
> CAST(col AT TIME ZONE INTERVAL '+00:00' AS DATETIME) AS ut
> FROM ts ORDER BY id;
+---------------------+---------------------+
| col | ut |
+---------------------+---------------------+
| 2020-01-01 10:10:10 | 2020-01-01 15:10:10 |
| 2019-12-31 23:40:10 | 2020-01-01 04:40:10 |
| 2020-01-01 13:10:10 | 2020-01-01 18:10:10 |
| 2020-01-01 10:10:10 | 2020-01-01 15:10:10 |
| 2020-01-01 04:40:10 | 2020-01-01 09:40:10 |
| 2020-01-01 18:10:10 | 2020-01-01 23:10:10 |
+---------------------+---------------------+
有关语法和其他示例的完整信息,请参阅CAST()
函数的描述。
要注意 MySQL 中日期值解释的某些属性:
-
MySQL 允许以字符串形式指定的值采用“宽松”格式,在这种格式中,任何标点符号都可以用作日期部分或时间部分之间的分隔符。在某些情况下,这种语法可能会产生误导。例如,像
'10:11:12'
这样的值可能看起来像一个时间值,因为有:
,但如果在日期上下文中使用,则会被解释为年份'2010-11-12'
。值'10:45:15'
会被转换为'0000-00-00'
,因为'45'
不是一个有效的月份。在日期和时间部分与小数秒部分之间唯一识别的分隔符是小数点。
-
服务器要求月份和日期值有效,而不仅仅是在 1 到 12 和 1 到 31 的范围内。在禁用严格模式的情况下,无效日期如
'2004-04-31'
会被转换为'0000-00-00'
并生成警告。启用严格模式时,无效日期会生成错误。要允许这样的日期,启用ALLOW_INVALID_DATES
。更多信息请参见 Section 7.1.11, “Server SQL Modes”。 -
MySQL 不接受在日期或月份列中包含零或不是有效日期的
TIMESTAMP
值。唯一的例外是特殊的“零”值'0000-00-00 00:00:00'
,如果 SQL 模式允许这个值。具体行为取决于是否启用了严格 SQL 模式和NO_ZERO_DATE
SQL 模式中的哪一个;参见 Section 7.1.11, “Server SQL Modes”。 -
包含 2 位数年份值的日期是模棱两可的,因为世纪未知。MySQL 使用以下规则解释 2 位数年份值:
-
范围在
00-69
的年份值变为2000-2069
。 -
范围在
70-99
的年份值变为1970-1999
。
另请参见 Section 13.2.9, “2-Digit Years in Dates”。
-
13.2.3 TIME 类型
MySQL 以'hh:mm:ss'
格式(对于较大的小时值为'hhh:mm:ss'
格式)检索和显示TIME
值。TIME
值的范围可以从'-838:59:59'
到'838:59:59'
。小时部分可能很大,因为TIME
类型不仅可以用于表示一天中的时间(必须小于 24 小时),还可以表示经过的时间或两个事件之间的时间间隔(可能远大于 24 小时,甚至为负)。
MySQL 以几种格式识别TIME
值,其中一些可以包括高达微秒(6 位数字)精度的尾随小数秒部分。请参阅 Section 11.1.3, “Date and Time Literals”了解更多信息。有关 MySQL 中小数秒支持的信息,请参阅 Section 13.2.6, “Fractional Seconds in Time Values”。特别是,插入到TIME
列中的值中的任何小数部分都将被存储而不是丢弃。包括小数部分后,TIME
值的范围为'-838:59:59.000000'
到'838:59:59.000000'
。
在为TIME
列分配缩写值时要小心。MySQL 将带有冒号的缩写TIME
值解释为当天的时间。也就是说,'11:12'
表示'11:12:00'
,而不是'00:11:12'
。MySQL 解释不带冒号的缩写值时,假设最右边的两位数字代表秒数(即经过的时间而不是当天的时间)。例如,你可能认为'1112'
和1112
表示'11:12:00'
(11 点 12 分后 12 分钟),但 MySQL 将其解释为'00:11:12'
(11 分钟 12 秒)。同样,'12'
和12
被解释为'00:00:12'
。
时间部分和小数秒部分之间唯一识别的分隔符是小数点。
默认情况下,超出TIME
范围但仍然有效的值将被剪切到范围的最近端点。例如,'-850:00:00'
和'850:00:00'
将转换为'-838:59:59'
和'838:59:59'
。无效的TIME
值将转换为'00:00:00'
。请注意,因为'00:00:00'
本身是一个有效的TIME
值,所以无法从存储在表中的'00:00:00'
的值中得知原始值是指定为'00:00:00'
还是无效的。
要对无效的TIME
值进行更严格的处理,请启用严格的 SQL 模式以导致错误发生。请参阅 Section 7.1.11, “Server SQL Modes”。
13.2.4 年份类型
YEAR
类型是用于表示年份值的 1 字节类型。它可以声明为带有 4 个字符的隐式显示宽度的YEAR
,或者等效地声明为带有显式显示宽度的YEAR(4)
。
注意
截至 MySQL 8.0.19,带有显式显示宽度的YEAR(4)
数据类型已被弃用,您应该期望在未来的 MySQL 版本中删除对其的支持。取而代之的是,使用没有显示宽度的YEAR
,其含义相同。
MySQL 8.0 不支持在旧版本 MySQL 中允许的 2 位YEAR(2)
数据类型。有关转换为 4 位YEAR
的说明,请参阅 2 位 YEAR(2)的限制和迁移到 4 位 YEAR,在 MySQL 5.7 参考手册中。
MySQL 以YYYY
格式显示YEAR
值,范围为1901
到2155
,以及0000
。
YEAR
接受各种格式的输入值:
-
作为范围在
'1901'
到'2155'
之间的 4 位数字字符串。 -
作为范围在
1901
到2155
之间的 4 位数字。 -
作为范围在
'0'
到'99'
之间的 1 位或 2 位字符串。MySQL 将范围在'0'
到'69'
和'70'
到'99'
之间的值转换为范围在2000
到2069
和1970
到1999
之间的YEAR
值。 -
作为范围在
0
到99
之间的 1 位或 2 位数字。MySQL 将范围在1
到69
和70
到99
之间的值转换为范围在2001
到2069
和1970
到1999
之间的YEAR
值。插入数字
0
的结果显示值为0000
,内部值为0000
。要插入零并将其解释为2000
,请将其指定为字符串'0'
或'00'
。 -
作为返回在
YEAR
上下文中可接受值的函数的结果,例如NOW()
。
如果未启用严格的 SQL 模式,MySQL 会将无效的YEAR
值转换为0000
。在严格的 SQL 模式下,尝试插入无效的YEAR
值会产生错误。
另请参阅第 13.2.9 节,“日期中的 2 位年份”。
13.2.5 TIMESTAMP 和 DATETIME 的自动初始化和更新
原文:
dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html
TIMESTAMP
和 DATETIME
列可以自动初始化并更新为当前日期和时间(即当前时间戳)。
对于表中的任何 TIMESTAMP
或 DATETIME
列,您可以将当前时间戳分配为默认值、自动更新值或两者:
-
自动初始化列对于未为该列指定值的插入行设置为当前时间戳。
-
自动更新列在行中的任何其他列的值从当前值更改时,将自动更新为当前时间戳。如果所有其他列都设置为它们的当前值,则自动更新列保持不变。要防止自动更新列在其他列更改时更新,请明确将其设置为当前值。即使其他列不更改,也要更新自动更新列,请明确将其设置为应具有的值(例如,将其设置为
CURRENT_TIMESTAMP
)。
此外,如果禁用了 explicit_defaults_for_timestamp
系统变量,则可以通过将其分配为 NULL
值来将任何 TIMESTAMP
(但不是 DATETIME
)列初始化或更新为当前日期和时间,除非已使用 NULL
属性定义了它以允许 NULL
值。
要指定自动属性,请在列定义中使用 DEFAULT CURRENT_TIMESTAMP
和 ON UPDATE CURRENT_TIMESTAMP
子句。子句的顺序无关紧要。如果列定义中同时存在两者,则任何一个都可以先出现。任何 CURRENT_TIMESTAMP
的同义词都与 CURRENT_TIMESTAMP
具有相同的含义。这些同义词包括 CURRENT_TIMESTAMP()
、NOW()
、LOCALTIME
、LOCALTIME()
、LOCALTIMESTAMP
和 LOCALTIMESTAMP()
。
使用DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
是特定于TIMESTAMP
和 DATETIME
的。DEFAULT
子句也可以用于指定常量(非自动)默认值(例如,DEFAULT 0
或 DEFAULT '2000-01-01 00:00:00'
)。
注意
以下示例使用DEFAULT 0
,这是一个可能会产生警告或错误的默认值,具体取决于是否启用了严格的 SQL 模式或 NO_ZERO_DATE
SQL 模式。请注意,TRADITIONAL
SQL 模式包括严格模式和 NO_ZERO_DATE
。请参阅 第 7.1.11 节,“服务器 SQL 模式”。
TIMESTAMP
或 DATETIME
列定义可以为默认值和自动更新值同时指定当前时间戳,其中一个指定当前时间戳,或者两者都不指定。不同列可以具有不同的自动属性组合。以下规则描述了可能性:
-
同时使用
DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
,列的默认值为当前时间戳,并且会自动更新为当前时间戳。CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
-
使用
DEFAULT
子句但没有ON UPDATE CURRENT_TIMESTAMP
子句,列具有给定的默认值,不会自动更新为当前时间戳。默认值取决于
DEFAULT
子句是否指定为CURRENT_TIMESTAMP
或常量值。使用CURRENT_TIMESTAMP
时,默认值为当前时间戳。CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP );
使用常量时,默认值为给定值。在这种情况下,列根本没有自动属性。
CREATE TABLE t1 ( ts TIMESTAMP DEFAULT 0, dt DATETIME DEFAULT 0 );
-
使用
ON UPDATE CURRENT_TIMESTAMP
子句和常量DEFAULT
子句,列会自动更新为当前时间戳,并具有给定的常量默认值。CREATE TABLE t1 ( ts TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, dt DATETIME DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP );
-
使用
ON UPDATE CURRENT_TIMESTAMP
子句但没有DEFAULT
子句,列会自动更新为当前时间戳,但不具有当前时间戳作为默认值。在这种情况下,默认值取决于类型。
TIMESTAMP
的默认值为 0,除非使用NULL
属性定义,此时默认值为NULL
。CREATE TABLE t1 ( ts1 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- default 0 ts2 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP -- default NULL );
DATETIME
的默认值为NULL
,除非使用NOT NULL
属性定义,此时默认值为 0。CREATE TABLE t1 ( dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0 );
时间戳
和 日期时间
列除非明确指定,否则没有自动属性,有一个例外:如果禁用了 explicit_defaults_for_timestamp
系统变量,则第一个 时间戳
列如果没有明确指定,则同时具有 DEFAULT CURRENT_TIMESTAMP
和 ON UPDATE CURRENT_TIMESTAMP
。要抑制第一个 时间戳
列的自动属性,可以使用以下策略之一:
-
启用
explicit_defaults_for_timestamp
系统变量。在这种情况下,指定自动初始化和更新的DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
子句是可用的,但除非明确包含在列定义中,否则不会分配给任何时间戳
列。 -
或者,如果禁用了
explicit_defaults_for_timestamp
,则执行以下操作之一:-
使用指定常量默认值的
DEFAULT
子句定义列。 -
指定
NULL
属性。这也会导致列允许NULL
值,这意味着您不能通过将列设置为NULL
来分配当前时间戳。将NULL
分配给列会将列设置为NULL
,而不是当前时间戳。要分配当前时间戳,请将列设置为CURRENT_TIMESTAMP
或类似NOW()
。
-
考虑以下表定义:
CREATE TABLE t1 (
ts1 TIMESTAMP DEFAULT 0,
ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t2 (
ts1 TIMESTAMP NULL,
ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t3 (
ts1 TIMESTAMP NULL DEFAULT 0,
ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
这些表具有以下属性:
-
在每个表定义中,第一个
时间戳
列没有自动初始化或更新。 -
这些表在处理
NULL
值的ts1
列上有所不同。对于t1
,ts1
是NOT NULL
,将其赋值为NULL
会将其设置为当前时间戳。对于t2
和t3
,ts1
允许NULL
,将其赋值为NULL
会将其设置为NULL
。 -
t2
和t3
在ts1
的默认值上有所不同。对于t2
,ts1
被定义为允许NULL
,因此在没有明确的DEFAULT
子句的情况下,默认值也为NULL
。对于t3
,ts1
允许NULL
但具有明确的默认值为 0。
如果 时间戳
或 日期时间
列定义在任何地方包含明确的小数秒精度值,则必须在整个列定义中使用相同的值。这是允许的:
CREATE TABLE t1 (
ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);
这是不允许的:
CREATE TABLE t1 (
ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(3)
);
时间戳初始化和 NULL 属性
如果禁用了explicit_defaults_for_timestamp
系统变量,则默认情况下TIMESTAMP
列为NOT NULL
,不能包含NULL
值,并且将NULL
分配给当前时间戳。要允许TIMESTAMP
列包含NULL
,请明确声明具有NULL
属性。在这种情况下,默认值也变为NULL
,除非使用指定不同默认值的DEFAULT
子句覆盖。DEFAULT NULL
可用于明确指定NULL
作为默认值。(对于未声明具有NULL
属性的TIMESTAMP
列,DEFAULT NULL
是无效的。)如果TIMESTAMP
列允许NULL
值,分配NULL
会将其设置为NULL
,而不是当前时间戳。
以下表包含几个允许NULL
值的TIMESTAMP
列:
CREATE TABLE t
(
ts1 TIMESTAMP NULL DEFAULT NULL,
ts2 TIMESTAMP NULL DEFAULT 0,
ts3 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
);
允许NULL
值的TIMESTAMP
列在插入时不会自动获取当前时间戳,除非满足以下条件之一:
-
其默认值被定义为
CURRENT_TIMESTAMP
,并且未为列指定任何值。 -
CURRENT_TIMESTAMP
或其任何同义词,如NOW()
,被明确插入到列中。
换句话说,只有在允许NULL
值的TIMESTAMP
列的定义中包含DEFAULT CURRENT_TIMESTAMP
时,才会自动初始化:
CREATE TABLE t (ts TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP);
如果TIMESTAMP
列允许NULL
值,但其定义不包括DEFAULT CURRENT_TIMESTAMP
,则必须明确插入与当前日期和时间对应的值。假设表t1
和t2
具有以下定义:
CREATE TABLE t1 (ts TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00');
CREATE TABLE t2 (ts TIMESTAMP NULL DEFAULT NULL);
要在任一表中的TIMESTAMP
列设置为插入时的当前时间戳,请明确地分配该值。例如:
INSERT INTO t2 VALUES (CURRENT_TIMESTAMP);
INSERT INTO t1 VALUES (NOW());
如果启用了explicit_defaults_for_timestamp
系统变量,则TIMESTAMP
列只允许NULL
值,如果声明了NULL
属性。此外,TIMESTAMP
列不允许将NULL
分配给当前时间戳,无论是否声明了NULL
或NOT NULL
属性。要分配当前时间戳,请将列设置为CURRENT_TIMESTAMP
或类似的同义词,如NOW()
。
13.2.6 时间值中的分数秒
MySQL 支持TIME
、DATETIME
和TIMESTAMP
值的分数秒,精度可达微秒(6 位数):
-
要定义包含分数秒部分的列,请使用
*
type_name*(*
fsp*)
的语法,其中type_name
是TIME
、DATETIME
或TIMESTAMP
,fsp
是分数秒精度。例如:CREATE TABLE t1 (t TIME(3), dt DATETIME(6));
如果给出
fsp
值,则必须在 0 到 6 的范围内。值为 0 表示没有分数部分。如果省略,则默认精度为 0。(这与标准 SQL 默认值 6 不同,以与以前的 MySQL 版本兼容。) -
将带有分数秒部分的
TIME
、DATE
或TIMESTAMP
值插入到具有较少分数位数但类型相同的列中会导致四舍五入。考虑以下创建和填充的表:CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) ); INSERT INTO fractest VALUES ('17:51:04.777', '2018-09-08 17:51:04.777', '2018-09-08 17:51:04.777');
时间值将被插入到表中并进行四舍五入:
mysql> SELECT * FROM fractest; +-------------+------------------------+------------------------+ | c1 | c2 | c3 | +-------------+------------------------+------------------------+ | 17:51:04.78 | 2018-09-08 17:51:04.78 | 2018-09-08 17:51:04.78 | +-------------+------------------------+------------------------+
当发生此类四舍五入时,不会发出警告或错误。此行为遵循 SQL 标准。
要进行截断插入值,需启用
TIME_TRUNCATE_FRACTIONAL
SQL 模式:SET @@sql_mode = sys.list_add(@@sql_mode, 'TIME_TRUNCATE_FRACTIONAL');
启用该 SQL 模式后,时间值将被截断插入:
mysql> SELECT * FROM fractest; +-------------+------------------------+------------------------+ | c1 | c2 | c3 | +-------------+------------------------+------------------------+ | 17:51:04.77 | 2018-09-08 17:51:04.77 | 2018-09-08 17:51:04.77 | +-------------+------------------------+------------------------+
-
接受时间参数的函数接受带有分数秒的值。从时间函数返回的值将根据需要包含分数秒。例如,不带参数的
NOW()
返回当前日期和时间,不包含分数部分,但可以使用 0 到 6 的可选参数指定返回值包含指定位数的分数秒部分。 -
时间文字的语法生成时间值:
DATE '*
str*'
、TIME '*
str*'
和TIMESTAMP '*
str*'
,以及 ODBC 语法的等效形式。如果指定,生成的值将包含尾随的分数秒部分。以前,时间类型关键字被忽略,这些构造产生字符串值。参见标准 SQL 和 ODBC 日期和时间文字
13.2.7 MySQL 使用哪种日历?
MySQL 使用的是所谓的推测格里高利历。
每个从儒略历转换为格里高利历的国家都必须在转换过程中丢弃至少十天。要了解这是如何运作的,请考虑 1582 年 10 月,当第一次儒略历到格里高利历的转换发生时。
星期一 | 星期二 | 星期三 | 星期四 | 星期五 | 星期六 | 星期日 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
10 月 4 日至 10 月 15 日之间没有日期。这种不连续称为转换。转换前的任何日期都是儒略历,转换后的日期都是格里高利历。转换期间的日期是不存在的。
在实际未使用的日期上应用的日历称为推测日历。因此,如果我们假设从未有过转换,格里高利规则始终适用,我们就有了一个推测格里高利历。这是 MySQL 使用的,也是标准 SQL 所要求的。因此,存储为 MySQL DATE
或 DATETIME
值的转换前日期必须进行调整以弥补差异。重要的是要意识到,转换并不是在所有国家同时发生的,而且发生得越晚,丢失的天数就越多。例如,在英国,这发生在 1752 年,当周三 9 月 2 日之后是周四 9 月 14 日。俄罗斯一直使用儒略历直到 1918 年,这个过程中丢失了 13 天,根据格里高利历,被普遍称为“十月革命”的事件实际发生在 11 月。
13.2.8 日期和时间类型之间的转换
原文:
dev.mysql.com/doc/refman/8.0/en/date-and-time-type-conversion.html
在一定程度上,您可以将一个时间类型的值转换为另一个时间类型。但是,可能会对值进行一些更改或丢失信息。在所有情况下,时间类型之间的转换受到生成类型的有效值范围的限制。例如,尽管DATE
、DATETIME
和TIMESTAMP
值都可以使用相同的格式集来指定,但这些类型的值范围并不相同。TIMESTAMP
值不能早于1970
年 UTC 或晚于'2038-01-19 03:14:07'
UTC。这意味着像'1968-01-01'
这样的日期,虽然作为DATE
或DATETIME
值是有效的,但作为TIMESTAMP
值是无效的,并转换为0
。
转换DATE
值:
-
转换为
DATETIME
或TIMESTAMP
值会添加一个时间部分'00:00:00'
,因为DATE
值不包含时间信息。 -
转换为
TIME
值没有用处;结果为'00:00:00'
。
转换DATETIME
和TIMESTAMP
值:
-
转换为
DATE
值考虑了小数秒并四舍五入时间部分。例如,'1999-12-31 23:59:59.499'
变为'1999-12-31'
,而'1999-12-31 23:59:59.500'
变为'2000-01-01'
。 -
转换为
TIME
值会丢弃日期部分,因为TIME
类型不包含日期信息。
对于将TIME
值转换为其他时间类型,日期部分使用CURRENT_DATE()
的值。TIME
被解释为经过的时间(而不是一天中的时间)并添加到日期上。这意味着结果的日期部分与当前日期不同,如果时间值超出范围从'00:00:00'
到'23:59:59'
。
假设当前日期为'2012-01-01'
。当TIME
值为'12:00:00'
,'24:00:00'
和'-12:00:00'
时,转换为DATETIME
或TIMESTAMP
值,结果分别为'2012-01-01 12:00:00'
,'2012-01-02 00:00:00'
和'2011-12-31 12:00:00'
。
将TIME
转换为DATE
类似,但从结果中丢弃时间部分:分别为'2012-01-01'
,'2012-01-02'
和'2011-12-31'
。
显式转换可用于覆盖隐式转换。例如,在比较DATE
和DATETIME
值时,DATE
值通过添加时间部分'00:00:00'
被强制转换为DATETIME
类型。要通过忽略DATETIME
值的时间部分执行比较,可以使用CAST()
函数如下方式:
*date_col* = CAST(*datetime_col* AS DATE)
将TIME
和DATETIME
值转换为数值形式(例如,通过添加+0
)取决于值是否包含小数秒部分。当N为 0(或省略)时,TIME(*N*)
或DATETIME(*N*)
转换为整数,当N大于 0 时,转换为具有N位小数位的DECIMAL
值:
mysql> SELECT CURTIME(), CURTIME()+0, CURTIME(3)+0;
+-----------+-------------+--------------+
| CURTIME() | CURTIME()+0 | CURTIME(3)+0 |
+-----------+-------------+--------------+
| 09:28:00 | 92800 | 92800.887 |
+-----------+-------------+--------------+
mysql> SELECT NOW(), NOW()+0, NOW(3)+0;
+---------------------+----------------+--------------------+
| NOW() | NOW()+0 | NOW(3)+0 |
+---------------------+----------------+--------------------+
| 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 |
+---------------------+----------------+--------------------+
13.2.9 日期中的 2 位数年份
具有 2 位数年份的日期值是模糊的,因为世纪未知。这些值必须被解释为 4 位数形式,因为 MySQL 在内部使用 4 位数存储年份。
对于DATETIME
、DATE
和TIMESTAMP
类型,MySQL 使用以下规则解释具有模糊年份值的日期:
-
范围在
00-69
之间的年份值变为2000-2069
。 -
范围在
70-99
之间的年份值变为1970-1999
。
对于YEAR
,规则相同,但有一个例外:将数字00
插入YEAR
会导致0000
而不是2000
。要为YEAR
指定零并将其解释为2000
,请将其指定为字符串'0'
或'00'
。
请记住,这些规则只是提供合理猜测的启发式规则,以确定数据值的含义。如果 MySQL 使用的规则无法产生所需的值,您必须提供包含 4 位数年份值的明确输入。
ORDER BY
可以正确排序具有 2 位数年份的YEAR
值。
一些函数,如MIN()
和MAX()
,将YEAR
转换为数字。这意味着具有 2 位数年份的值无法与这些函数正常工作。在这种情况下的修复方法是将YEAR
转换为 4 位数年份格式。
13.3 字符串数据类型
13.3.1 字符串数据类型语法
13.3.2 CHAR 和 VARCHAR 类型
13.3.3 BINARY 和 VARBINARY 类型
13.3.4 BLOB 和 TEXT 类型
13.3.5 ENUM 类型
13.3.6 SET 类型
字符串数据类型包括 CHAR
, VARCHAR
, BINARY
, VARBINARY
, BLOB
, TEXT
, ENUM
, 和 SET
.
有关字符串数据类型的存储要求,请参阅 第 13.7 节,“数据类型存储要求”。
关于操作字符串值的函数描述,请参阅 第 14.8 节,“字符串函数和运算符”。
13.3.1 字符串数据类型语法
字符串数据类型包括CHAR
, VARCHAR
, BINARY
, VARBINARY
, BLOB
, TEXT
, ENUM
, 和 SET
。
在某些情况下,MySQL 可能会将字符串列更改为与CREATE TABLE
或ALTER TABLE
语句中给出的类型不同的类型。请参阅第 15.1.20.7 节,“静默列规范更改”。
对于字符串列的定义(CHAR
, VARCHAR
, 和 TEXT
类型), MySQL 以字符单位解释长度规范。对于二进制字符串列的定义(BINARY
, VARBINARY
, 和 BLOB
类型), MySQL 以字节单位解释长度规范。
字符串数据类型CHAR
, VARCHAR
, TEXT
类型, ENUM
, SET
, 和任何同义词的列定义可以指定列字符集和排序规则:
-
CHARACTER SET
指定字符集。如果需要,可以使用COLLATE
属性指定字符集的排序规则,以及任何其他属性。例如:CREATE TABLE t ( c1 VARCHAR(20) CHARACTER SET utf8mb4, c2 TEXT CHARACTER SET latin1 COLLATE latin1_general_cs );
此表定义创建一个名为
c1
的列,其字符集为utf8mb4
,具有该字符集的默认排序规则,并创建一个名为c2
的列,其字符集为latin1
,具有区分大小写(_cs
)的排序规则。当
CHARACTER SET
和COLLATE
属性中的一个或两个缺失时,关于分配字符集和排序规则的规则在第 12.3.5 节,“列字符集和排序”中描述。CHARSET
是CHARACTER SET
的同义词。 -
为字符串数据类型指定
CHARACTER SET binary
属性会导致该列被创建为相应的二进制字符串数据类型:CHAR
变为BINARY
,VARCHAR
变为VARBINARY
,TEXT
变为BLOB
。对于ENUM
和SET
数据类型,不会发生这种情况;它们将按声明创建。假设您使用以下定义指定一个表:CREATE TABLE t ( c1 VARCHAR(10) CHARACTER SET binary, c2 TEXT CHARACTER SET binary, c3 ENUM('a','b','c') CHARACTER SET binary );
结果表的定义如下:
CREATE TABLE t ( c1 VARBINARY(10), c2 BLOB, c3 ENUM('a','b','c') CHARACTER SET binary );
-
BINARY
属性是 MySQL 的非标准扩展,是指定列字符集的二进制 (_bin
) 校对的简写(如果未指定列字符集,则是表默认字符集的二进制校对)。在这种情况下,比较和排序是基于数字字符代码值的。假设您使用以下定义指定一个表:CREATE TABLE t ( c1 VARCHAR(10) CHARACTER SET latin1 BINARY, c2 TEXT BINARY ) CHARACTER SET utf8mb4;
结果表的定义如下:
CREATE TABLE t ( c1 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin, c2 TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin ) CHARACTER SET utf8mb4;
在 MySQL 8.0 中,
BINARY
属性的这种非标准用法是模棱两可的,因为utf8mb4
字符集有多个_bin
校对。从 MySQL 8.0.17 开始,BINARY
属性已被弃用,您应该期望在将来的 MySQL 版本中删除对其的支持。应用程序应调整为使用显式的_bin
校对。使用
BINARY
指定数据类型或字符集的用法保持不变。 -
ASCII
属性是CHARACTER SET latin1
的简写。在较旧的 MySQL 版本中受支持,但在 MySQL 8.0.28 及更高版本中已被弃用;请使用CHARACTER SET
替代。 -
UNICODE
属性是CHARACTER SET ucs2
的简写。在较旧的 MySQL 版本中受支持,但在 MySQL 8.0.28 及更高版本中已被弃用;请使用CHARACTER SET
替代。
字符列的比较和排序基于分配给列的校对规则。对于 CHAR
、VARCHAR
、TEXT
、ENUM
和 SET
数据类型,您可以声明一个带有二进制 (_bin
) 校对或 BINARY
属性的列,以使比较和排序使用底层字符代码值而不是词法顺序。
有关 MySQL 中字符集使用的更多信息,请参阅 第十二章,字符集、校对规则、Unicode。
-
[NATIONAL] CHAR[(*
M*)] [CHARACTER SET *
charset_name*] [COLLATE *
collation_name*]
固定长度的字符串,在存储时总是用空格右填充到指定长度。
M
代表列长度(以字符为单位)。M
的范围是 0 到 255。如果省略M
,长度为 1。注意
当检索
CHAR
值时,尾随空格会被移除,除非启用了PAD_CHAR_TO_FULL_LENGTH
SQL 模式。CHAR
是CHARACTER
的简写。NATIONAL CHAR
(或其等效的简写形式,NCHAR
)是定义CHAR
列应使用某个预定义字符集的标准 SQL 方式。MySQL 使用utf8mb3
作为这个预定义字符集。第 12.3.7 节,“国家字符集”。CHAR BYTE
数据类型是BINARY
数据类型的别名。这是一个兼容性特性。MySQL 允许创建类型为
CHAR(0)
的列。这在必须符合依赖于列存在但实际上不使用其值的旧应用程序时非常有用。当您需要一个只能取两个值的列时,CHAR(0)
也非常好:定义为CHAR(0) NULL
的列仅占用一个位,并且只能取NULL
和''
(空字符串)这两个值。 -
[NATIONAL] VARCHAR(*
M*) [字符集 *
charset_name*] [校对 *
collation_name*]
可变长度字符串。
M
表示最大列长度(以字符为单位)。M
的范围是 0 到 65,535。VARCHAR
的有效最大长度取决于最大行大小(65,535 字节,在所有列之间共享)和所使用的字符集。例如,utf8mb3
字符可能每个字符需要最多三个字节,因此使用utf8mb3
字符集的VARCHAR
列最大可以声明为 21,844 个字符。参见第 10.4.7 节,“表列计数和行大小限制”。MySQL 将
VARCHAR
值存储为 1 字节或 2 字节长度前缀加数据。长度前缀指示值中的字节数。如果值不超过 255 字节,则VARCHAR
列使用一个长度字节,如果值可能超过 255 字节,则使用两个长度字节。注意
MySQL 遵循标准 SQL 规范,不会从
VARCHAR
值中删除尾随空格。VARCHAR
是CHARACTER VARYING
的简写。NATIONAL VARCHAR
是定义VARCHAR
列应使用某个预定义字符集的标准 SQL 方式。MySQL 使用utf8mb3
作为这个预定义字符集。第 12.3.7 节,“国家字符集”。NVARCHAR
是NATIONAL VARCHAR
的简写。 -
BINARY
类型类似于CHAR
类型,但存储的是二进制字节字符串而不是非二进制字符字符串。可选长度M
表示列长度(以字节为单位)。如果省略,M
默认为 1。 -
VARBINARY(*
M*)
VARBINARY
类型类似于VARCHAR
类型,但存储的是二进制字节字符串而不是非二进制字符字符串。M
表示最大列长度(以字节为单位)。 -
TINYBLOB
最大长度为 255(2⁸ − 1)字节的
BLOB
列。每个TINYBLOB
值都使用一个 1 字节长度前缀来存储,指示值中的字节数。 -
TINYTEXT [字符集 *
charset_name*] [校对 *
collation_name*]
最大长度为 255(2⁸ − 1)个字符的
TEXT
列。如果值包含多字节字符,则有效最大长度会减少。每个TINYTEXT
值都使用一个 1 字节长度前缀来存储,指示值中的字节数。 -
最大长度为 65,535(2¹⁶ − 1)字节的
BLOB
列。每个BLOB
值都使用一个 2 字节长度前缀来存储,指示值中的字节数。可以为此类型指定可选长度
M
。如果这样做,MySQL 将创建一个足以容纳M
字节长值的最小BLOB
类型列。 -
TEXT[(*
M*)] [字符集 *
charset_name*] [校对 *
collation_name*]
一个最大长度为 65,535(2¹⁶ − 1)个字符的
TEXT
列。如果值包含多字节字符,则有效最大长度会更少。每个TEXT
值都使用一个 2 字节长度前缀来指示值中的字节数。可以为此类型指定一个可选长度
M
。如果这样做,MySQL 会创建一个足以容纳M
个字符长的最小TEXT
类型列。 -
MEDIUMBLOB
一个最大长度为 16,777,215(2²⁴ − 1)字节的
BLOB
列。每个MEDIUMBLOB
值都使用一个 3 字节长度前缀来指示值中的字节数。 -
MEDIUMTEXT [字符集 *
charset_name*] [校对 *
collation_name*]
一个最大长度为 16,777,215(2²⁴ − 1)个字符的
TEXT
列。如果值包含多字节字符,则有效最大长度会更少。每个MEDIUMTEXT
值都使用一个 3 字节长度前缀来指示值中的字节数。 -
LONGBLOB
一个最大长度为 4,294,967,295 或 4GB(2³² − 1)字节的
BLOB
列。LONGBLOB
列的有效最大长度取决于客户端/服务器协议中配置的最大数据包大小和可用内存。每个LONGBLOB
值都使用一个 4 字节长度前缀来指示值中的字节数。 -
LONGTEXT [字符集 *
charset_name*] [校对 *
collation_name*]
一个最大长度为 4,294,967,295 或 4GB(2³² − 1)个字符的
TEXT
列。如果值包含多字节字符,则有效最大长度会更少。LONGTEXT
列的有效最大长度还取决于客户端/服务器协议中配置的最大数据包大小和可用内存。每个LONGTEXT
值都使用一个 4 字节长度前缀来指示值中的字节数。 -
ENUM('*
value1*','*
value2*',...) [字符集 *
charset_name*] [校对 *
collation_name*]
一个枚举。一个字符串对象,只能有一个值,从值列表
'*
value1*'
,'*
value2*'
,...
,NULL
或特殊的''
错误值中选择。ENUM
值在内部表示为整数。ENUM
列最多可以有 65,535 个不同元素。单个
ENUM
元素的最大支持长度为M
<= 255,且(M
xw
) <= 1020,其中M
是元素文字长度,w
是字符集中最大长度字符所需的字节数。 -
SET('*
value1*','*
value2*',...) [字符集 *
charset_name*] [校对 *
collation_name*]
一个集合。一个字符串对象,可以有零个或多个值,每个值必须从值列表
'*
value1*'
,'*
value2*'
,...
SET
中选择的值内部表示为整数。SET
列最多可以有 64 个不同成员。单个
SET
元素的最大支持长度为M
<= 255,且(M
xw
) <= 1020,其中M
是元素文字长度,w
是字符集中最大长度字符所需的字节数。
13.3.2 CHAR 和 VARCHAR 类型
CHAR
和VARCHAR
类型相似,但在存储和检索方式、最大长度以及是否保留尾随空格方面有所不同。
CHAR
和VARCHAR
类型声明的长度指示您希望存储的最大字符数。例如,CHAR(30)
可以容纳最多 30 个字符。
CHAR
列的长度在创建表时声明为固定长度。长度可以是 0 到 255 之间的任何值。存储CHAR
值时,它们会右填充空格以达到指定长度。检索CHAR
值时,除非启用了PAD_CHAR_TO_FULL_LENGTH
SQL 模式,否则会移除尾随空格。
VARCHAR
列中的值是可变长度字符串。长度可以指定为 0 到 65,535 之间的值。VARCHAR
的有效最大长度取决于最大行大小(65,535 字节,这些字节在所有列之间共享)和所使用的字符集。参见第 10.4.7 节,“表列计数和行大小限制”。
与CHAR
相反,VARCHAR
值存储为 1 字节或 2 字节长度前缀加数据。长度前缀指示值中的字节数。如果值不超过 255 字节,则列使用一个长度字节,如果值可能需要超过 255 字节,则使用两个长度字节。
如果未启用严格的 SQL 模式,并且将值分配给超出列最大长度的CHAR
或VARCHAR
列,则该值将被截断以适应,并生成警告。对于非空格字符的截断,您可以通过使用严格的 SQL 模式来导致错误发生(而不是警告),并抑制值的插入。参见第 7.1.11 节,“服务器 SQL 模式”。
对于VARCHAR
列,在插入之前会截断超出列长度的尾随空格,并生成警告,无论使用的 SQL 模式如何。对于CHAR
列,无论使用的 SQL 模式如何,插入值时都会静默执行超出尾随空格的截断。
存储VARCHAR
值时不会填充。在存储和检索值时,尾随空格会被保留,符合标准 SQL。
以下表格通过展示将各种字符串值存储到CHAR(4)
和VARCHAR(4)
列中的结果(假设列使用单字节字符集如latin1
)来说明CHAR
和VARCHAR
之间的差异。
值 | CHAR(4) |
存储空间 | VARCHAR(4) |
存储空间 |
---|---|---|---|---|
'' |
' ' |
4 字节 | '' |
1 字节 |
'ab' |
'ab ' |
4 字节 | 'ab' |
3 字节 |
'abcd' |
'abcd' |
4 字节 | 'abcd' |
5 字节 |
'abcdefgh' |
'abcd' |
4 字节 | 'abcd' |
5 字节 |
在表的最后一行显示的值仅在不使用严格 SQL 模式时适用;如果启用了严格模式,超过列长度的值将不会被存储,并且会导致错误。
InnoDB
将长度大于或等于 768 字节的固定长度字段编码为可变长度字段,可以存储在页外。例如,如果字符集的最大字节长度大于 3,如utf8mb4
,则CHAR(255)
列可以超过 768 字节。
如果给定值存储到CHAR(4)
和VARCHAR(4)
列中,从列中检索的值并不总是相同,因为从CHAR
列中检索时会删除尾随空格。以下示例说明了这种差异:
mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO vc VALUES ('ab ', 'ab ');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab ) | (ab) |
+---------------------+---------------------+
1 row in set (0.06 sec)
CHAR
、VARCHAR
和TEXT
列中的值根据分配给列的字符集排序和比较。
MySQL 排序具有PAD SPACE
填充属性,除了基于 UCA 9.0.0 及更高版本的 Unicode 排序具有NO PAD
填充属性。 (参见第 12.10.1 节,“Unicode 字符集”).
要确定排序的填充属性,请使用INFORMATION_SCHEMA
COLLATIONS
表,该表具有一个PAD_ATTRIBUTE
列。
对于非二进制字符串(CHAR
、VARCHAR
和TEXT
值),字符串排序填充属性决定了在字符串末尾的尾随空格比较中的处理方式。NO PAD
排序将尾随空格视为比较中的重要部分,就像任何其他字符一样。PAD SPACE
排序将尾随空格视为比较中不重要的部分;字符串将在不考虑尾随空格的情况下进行比较。参见比较中的尾随空格处理。服务器 SQL 模式对于尾随空格的比较行为没有影响。
注意
有关 MySQL 字符集和排序的更多信息,请参见第十二章,“字符集、排序、Unicode”。有关存储要求的其他信息,请参见第 13.7 节,“数据类型存储要求”。
对于那些尾随填充字符被剥离或比较忽略它们的情况,如果一个列有一个需要唯一值的索引,插入到列中仅在尾随填充字符数量不同的值会导致重复键错误。例如,如果一个表包含'a'
,尝试存储'a '
会导致重复键错误。
13.3.3 BINARY 和 VARBINARY 类型
BINARY
和 VARBINARY
类型类似于 CHAR
和 VARCHAR
,只是它们存储二进制字符串而不是非二进制字符串。也就是说,它们存储字节字符串而不是字符字符串。这意味着它们具有 binary
字符集和校对,比较和排序基于值中字节的数值。
BINARY
和 VARBINARY
的最大长度与 CHAR
和 VARCHAR
的最大长度相同,只是 BINARY
和 VARBINARY
的长度是以字节而不是字符计量的。
BINARY
和 VARBINARY
数据类型与 CHAR BINARY
和 VARCHAR BINARY
数据类型不同。对于后者,BINARY
属性不会导致列被视为二进制字符串列。相反,它会导致使用列字符集的二进制 (_bin
) 校对(如果未指定列字符集,则使用表默认字符集),并且列本身存储非二进制字符字符串而不是二进制字节字符串。例如,如果默认字符集是 utf8mb4
,CHAR(5) BINARY
被视为 CHAR(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
。这与 BINARY(5)
不同,后者存储具有 binary
字符集和校对的 5 字节二进制字符串。有关 binary
字符集的 binary
校对与非二进制字符集的 _bin
校对之间的差异的信息,请参见 Section 12.8.5, “The binary Collation Compared to _bin Collations”。
如果未启用严格的 SQL 模式,并且将值分配给超出列最大长度的 BINARY
或 VARBINARY
列,则该值将被截断以适应,并生成警告。对于截断的情况,要导致发生错误(而不是警告)并阻止插入该值,请使用严格的 SQL 模式。请参见 Section 7.1.11, “Server SQL Modes”。
存储 BINARY
值时,它们会使用填充值右填充到指定长度。填充值为 0x00
(零字节)。对于插入,值会使用 0x00
右填充,检索时不会删除尾随字节。在比较中,所有字节都是重要的,包括 ORDER BY
和 DISTINCT
操作。0x00
和空格在比较中不同,0x00
排在空格之前。
例如:对于 BINARY(3)
列,'a '
在插入时变为 'a \0'
。'a\0'
在插入时变为 'a\0\0'
。这两个插入值在检索时保持不变。
对于VARBINARY
,插入时不进行填充,检索时不剥离任何字节。在比较中,所有字节都是重要的,包括ORDER BY
和DISTINCT
操作。在比较中,0x00
和空格是不同的,0x00
在排序中排在空格之前。
对于那些剥离尾随填充字节或比较忽略它们的情况,如果列具有需要唯一值的索引,那么在列中插入仅在尾随填充字节数量上不同的值会导致重复键错误。例如,如果表中包含'a'
,尝试存储'a\0'
会导致重复键错误。
如果您计划使用BINARY
数据类型存储二进制数据,并且需要检索的值与存储的值完全相同,那么您应该仔细考虑前导填充和剥离特性。以下示例说明了BINARY
值的0x00
填充如何影响列值比较:
mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t SET c = 'a';
Query OK, 1 row affected (0.01 sec)
mysql> SELECT HEX(c), c = 'a', c = 'a\0\0' from t;
+--------+---------+-------------+
| HEX(c) | c = 'a' | c = 'a\0\0' |
+--------+---------+-------------+
| 610000 | 0 | 1 |
+--------+---------+-------------+
1 row in set (0.09 sec)
如果检索的值必须与存储时指定的值完全相同且没有填充,则最好使用VARBINARY
或BLOB
数据类型之一。
注意
在mysql客户端中,二进制字符串使用十六进制表示,取决于--binary-as-hex
选项的值。有关该选项的更多信息,请参见 Section 6.5.1, “mysql — The MySQL Command-Line Client”。
13.3.4 BLOB 和 TEXT 类型
BLOB
是可以容纳可变数量数据的二进制大对象。四种BLOB
类型分别是TINYBLOB
、BLOB
、MEDIUMBLOB
和LONGBLOB
。它们仅在可以容纳的值的最大长度上有所不同。四种TEXT
类型是TINYTEXT
、TEXT
、MEDIUMTEXT
和LONGTEXT
。这些与四种BLOB
类型对应,并具有相同的最大长度和存储要求。参见第 13.7 节,“数据类型存储要求”。
BLOB
值被视为二进制字符串(字节字符串)。它们具有binary
字符集和排序规则,比较和排序基于列值中字节的数值。TEXT
值被视为非二进制字符串(字符字符串)。它们具有除binary
之外的字符集,并且根据字符集的排序规则进行排序和比较。
如果未启用严格的 SQL 模式并且将值分配给超出列的最大长度的BLOB
或TEXT
列,则该值将被截断以适应并生成警告。对于非空格字符的截断,您可以通过使用严格的 SQL 模式导致错误发生(而不是警告)并抑制值的插入。参见第 7.1.11 节,“服务器 SQL 模式”。
要插入TEXT
列的值中多余的尾随空格截断总是生成警告,无论 SQL 模式如何。
对于TEXT
和BLOB
列,在插入时不会填充,选择时也不会去除任何字节。
如果对TEXT
列进行索引,索引条目比较在末尾填充空格。这意味着,如果索引需要唯一值,则对于仅在尾随空格数量上不同的值会导致重复键错误。例如,如果表包含'a'
,则尝试存储'a '
会导致重复键错误。对于BLOB
列则不是这样。
在大多数方面,您可以将BLOB
列视为可以任意大的VARBINARY
列。同样,您可以将TEXT
列视为VARCHAR
列。BLOB
和TEXT
与VARBINARY
和VARCHAR
在以下方面有所不同:
-
对于
BLOB
和TEXT
列上的索引,必须指定索引前缀长度。对于CHAR
和VARCHAR
,前缀长度是可选的。参见第 10.3.5 节,“列索引”。 -
BLOB
和TEXT
列不能有DEFAULT
值。
如果在TEXT
数据类型中使用BINARY
属性,则该列将被分配为列字符集的二进制(_bin
)排序规则。
LONG
和LONG VARCHAR
映射到MEDIUMTEXT
数据类型。这是一个兼容性特性。
MySQL Connector/ODBC 将BLOB
值定义为LONGVARBINARY
,将TEXT
值定义为LONGVARCHAR
。
因为BLOB
和TEXT
值可能非常长,所以在使用它们时可能会遇到一些限制:
-
在排序时只使用列的前
max_sort_length
字节。max_sort_length
的默认值为 1024。您可以通过在服务器启动或运行时增加max_sort_length
的值来使更多字节在排序或分组中起作用。任何客户端都可以更改其会话max_sort_length
变量的值:mysql> SET max_sort_length = 2000; mysql> SELECT id, comment FROM t -> ORDER BY comment;
-
在使用临时表处理的查询结果中存在
BLOB
或TEXT
列的实例会导致服务器在磁盘上而不是内存中使用表,因为MEMORY
存储引擎不支持这些数据类型(参见第 10.4.4 节,“MySQL 中的内部临时表使用”)。使用磁盘会导致性能损失,因此只有在真正需要时才在查询结果中包含BLOB
或TEXT
列。例如,避免使用SELECT *
,它会选择所有列。 -
BLOB
或TEXT
对象的最大大小由其类型确定,但实际上您可以在客户端和服务器之间传输的最大值取决于可用内存量和通信缓冲区的大小。您可以通过更改max_allowed_packet
变量的值来更改消息缓冲区大小,但必须同时为服务器和客户端程序执行此操作。例如,mysql和mysqldump都允许您更改客户端端的max_allowed_packet
值。请参阅第 7.1.1 节,“配置服务器”,第 6.5.1 节,“mysql — MySQL 命令行客户端”和第 6.5.4 节,“mysqldump — 数据库备份程序”。您可能还想比较数据包大小和您存储的数据对象的大小与存储要求的大小,参见第 13.7 节,“数据类型存储要求”
每个BLOB
或TEXT
值在内部由单独分配的对象表示。这与所有其他数据类型形成对比,其他数据类型在打开表时为每列分配存储空间。
在某些情况下,将二进制数据(如媒体文件)存储在BLOB
或TEXT
列中可能是可取的。您可能会发现 MySQL 的字符串处理函数在处理此类数据时非常有用。请参阅第 14.8 节,“字符串函数和运算符”。出于安全和其他原因,通常最好使用应用程序代码来处理此类数据,而不是给予应用程序用户FILE
权限。您可以在 MySQL 论坛(forums.mysql.com/
)讨论各种语言和平台的具体情况。
注意
在mysql客户端中,二进制字符串以十六进制表示,具体取决于--binary-as-hex
的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”。
13.3.5 ENUM 类型
ENUM
是一个字符串对象,其值是在表创建时在列规范中明确枚举的允许值列表中选择的。
请参见第 13.3.1 节,“字符串数据类型语法”以获取ENUM
类型的语法和长度限制。
ENUM
类型具有以下优点:
-
在列具有有限可能值集的情况下紧凑的数据存储。您指定的输入值字符串会自动编码为数字。有关
ENUM
类型的存储要求,请参见第 13.7 节,“数据类型存储要求”。 -
可读的查询和输出。数字在查询结果中被翻译回相应的字符串。
以及需要考虑的潜在问题:
-
如果您创建看起来像数字的枚举值,很容易混淆文字值与其内部索引号,如枚举限制中所解释的那样。
-
在
ORDER BY
子句中使用ENUM
列需要额外小心,如枚举排序中所解释的那样。 -
创建和使用 ENUM 列
-
枚举文字的索引值
-
枚举文字的处理
-
空或 NULL 的枚举值
-
枚举排序
-
枚举限制
创建和使用 ENUM 列
枚举值必须是带引号的字符串文字。例如,您可以像这样创建具有ENUM
列的表:
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),
('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
+---------+--------+
| name | size |
+---------+--------+
| t-shirt | medium |
+---------+--------+
UPDATE shirts SET size = 'small' WHERE size = 'large';
COMMIT;
将值为'medium'
的 1 百万行插入到此表中将需要 1 百万字节的存储空间,而如果您将实际字符串'medium'
存储在VARCHAR
列中,则需要 6 百万字节。
枚举文字的索引值
每个枚举值都有一个索引:
-
在列规范中列出的元素被分配索引号,从 1 开始。
-
空字符串错误值的索引值为 0。这意味着您可以使用以下
SELECT
语句查找分配了无效ENUM
值的行:mysql> SELECT * FROM *tbl_name* WHERE *enum_col*=0;
-
NULL
值的索引为NULL
。 -
这里的“索引”术语指的是枚举值列表中的位置。它与表索引无关。
例如,指定为ENUM('Mercury', 'Venus', 'Earth')
的列可以具有此处显示的任何值。每个值的索引也显示在这里。
值 | 索引 |
---|---|
NULL |
NULL |
'' |
0 |
'水星' |
1 |
'金星' |
2 |
'地球' |
3 |
一个ENUM
列最多可以有 65,535 个不同的元素。
如果在数值上下文中检索ENUM
值,则返回列值的索引。例如,可以像这样从ENUM
列中检索数值:
mysql> SELECT *enum_col*+0 FROM *tbl_name*;
诸如SUM()
或AVG()
之类的期望数值参数的函数在必要时将参数转换为数字。对于ENUM
值,索引号用于计算。
处理枚举文字
在创建表时,表定义中的ENUM
成员值的尾随空格会被自动删除。
检索时,存储到ENUM
列中的值将使用在列定义中使用的大小写形式显示。请注意,ENUM
列可以分配字符集和排序规则。对于二进制或区分大小写的排序规则,在为列分配值时会考虑大小写形式。
如果将一个数字存储到一个ENUM
列中,该数字将被视为可能值的索引,存储的值是具有该索引的枚举成员。(但是,这在LOAD DATA
中不起作用,因为它将所有输入视为字符串。)如果将数字值引用起来,如果在枚举值列表中没有匹配的字符串,它仍然被解释为索引。因此,不建议定义一个具有看起来像数字的枚举值的ENUM
列,因为这很容易变得令人困惑。例如,以下列具有字符串值为'0'
,'1'
和'2'
的枚举成员,但索引值为1
,2
和3
:
numbers ENUM('0','1','2')
如果存储2
,它被解释为索引值,并变为'1'
(具有索引 2 的值)。如果存储'2'
,它匹配一个枚举值,因此存储为'2'
。如果存储'3'
,它不匹配任何枚举值,因此被视为索引并变为'2'
(具有索引 3 的值)。
mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1 |
| 2 |
| 2 |
+---------+
要确定ENUM
列的所有可能值,请使用SHOW COLUMNS FROM *
tbl_name* LIKE '*
enum_col*'
并解析输出的Type
列中的ENUM
定义。
在 C API 中,ENUM
值以字符串形式返回。有关使用结果集元数据将其与其他字符串区分开的信息,请参阅 C API 基本数据结构。
空或 NULL 枚举值
在某些情况下,枚举值也可以是空字符串(''
)或NULL
:
-
如果向
ENUM
中插入无效值(即不在允许值列表中的字符串),则插入空字符串作为特殊错误值。此字符串可以通过该字符串的数值为 0 来与“正常”空字符串区分。有关枚举值的数值索引的详细信息,请参阅枚举文字的索引值。如果启用了严格的 SQL 模式,则尝试插入无效的
ENUM
值会导致错误。 -
如果声明
ENUM
列允许NULL
,则NULL
值是列的有效值,且默认值为NULL
。如果声明ENUM
列为NOT NULL
,其默认值为允许值列表的第一个元素。
枚举排序
ENUM
值根据它们的索引号排序,这取决于在列规范中列出枚举成员的顺序。例如,对于ENUM('b', 'a')
,'b'
在'a'
之前排序。空字符串在非空字符串之前排序,NULL
值在所有其他枚举值之前排序。
为了在对ENUM
列使用ORDER BY
子句时避免意外结果,请使用以下技术之一:
-
按字母顺序指定
ENUM
列表。 -
确保通过编码
ORDER BY CAST(*
col* AS CHAR)
或ORDER BY CONCAT(*
col*)
对列进行字典排序而不是按索引号排序。
枚举限制
枚举值不能是表达式,即使是评估为字符串值的表达式也不行。
例如,此CREATE TABLE
语句不起作用,因为CONCAT
函数不能用于构造枚举值:
CREATE TABLE sizes (
size ENUM('small', CONCAT('med','ium'), 'large')
);
您也不能将用户变量用作枚举值。这对语句不起作用:
SET @mysize = 'medium';
CREATE TABLE sizes (
size ENUM('small', @mysize, 'large')
);
我们强烈建议不要将数字用作枚举值,因为它不会节省适当TINYINT
或SMALLINT
类型的存储空间,并且如果错误引用ENUM
值,很容易混淆字符串和底层数值(可能不同)。如果将数字用作枚举值,请始终将其括在引号中。如果省略引号,则该数字被视为索引。请参阅枚举文字的处理以查看即使引用的数字也可能被错误地用作数值索引值的情况。
定义中的重复值会导致警告,如果启用了严格的 SQL 模式,则会导致错误。
13.3.6 SET
类型
SET
是一个字符串对象,可以具有零个或多个值,每个值必须从创建表时指定的允许值列表中选择。由于SET
列值由逗号(,
)分隔的成员指定,因此SET
成员值本身不应包含逗号。
例如,指定为SET('one', 'two') NOT NULL
的列可以具有以下任何值:
''
'one'
'two'
'one,two'
SET
列最多可以有 64 个不同的成员。
定义中的重复值会导致警告,如果启用了严格的 SQL 模式,则会导致错误。
在创建表时,SET
成员值的尾随空格会自动删除。
有关SET
类型的存储要求,请参见字符串类型存储要求。
有关SET
类型的语法和长度限制,请参见第 13.3.1 节,“字符串数据类型语法”。
当检索时,存储在SET
列中的值将以列定义中使用的大小写形式显示。请注意,SET
列可以分配字符集和排序规则。对于二进制或区分大小写的排序规则,分配值给列时会考虑大小写。
MySQL 以数字形式存储SET
值,存储值的低位对应于第一个集合成员。如果在数字上下文中检索SET
值,则检索到的值具有对应于构成列值的集合成员的位设置。例如,可以像这样从SET
列中检索数值:
mysql> SELECT *set_col*+0 FROM *tbl_name*;
如果将数字存储到SET
列中,则在数字的二进制表示中设置的位确定列值中的集合成员。对于指定为SET('a','b','c','d')
的列,成员具有以下十进制和二进制值。
SET 成员 |
十进制值 | 二进制值 |
---|---|---|
'a' |
1 |
0001 |
'b' |
2 |
0010 |
'c' |
4 |
0100 |
'd' |
8 |
1000 |
如果将值9
分配给此列,即二进制为1001
,因此选择第一个和第四个SET
值成员'a'
和'd'
,得到的值为'a,d'
。
对于包含多个SET
元素的值,插入值时元素的顺序无关紧要。同样,给定元素在值中列出的次数也无关紧要。稍后检索值时,值中的每个元素只出现一次,并且元素按照在创建表时指定的顺序列出。假设列被指定为SET('a','b','c','d')
:
mysql> CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
如果插入值'a,d'
、'd,a'
、'a,d,d'
、'a,d,a'
和'd,a,d'
:
mysql> INSERT INTO myset (col) VALUES
-> ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
然后检索这些值时,所有这些值都显示为'a,d'
:
mysql> SELECT col FROM myset;
+------+
| col |
+------+
| a,d |
| a,d |
| a,d |
| a,d |
| a,d |
+------+
5 rows in set (0.04 sec)
如果将SET
列设置为不支持的值,则该值将被忽略并发出警告:
mysql> INSERT INTO myset (col) VALUES ('a,d,d,s');
Query OK, 1 row affected, 1 warning (0.03 sec)
mysql> SHOW WARNINGS;
+---------+------+------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------+
| Warning | 1265 | Data truncated for column 'col' at row 1 |
+---------+------+------------------------------------------+
1 row in set (0.04 sec)
mysql> SELECT col FROM myset;
+------+
| col |
+------+
| a,d |
| a,d |
| a,d |
| a,d |
| a,d |
| a,d |
+------+
6 rows in set (0.01 sec)
如果启用了严格的 SQL 模式,则尝试插入无效的SET
值将导致错误。
SET
值按数字顺序排序。NULL
值在非NULL
SET
值之前排序。
诸如SUM()
或AVG()
之类的期望数值参数的函数,如果需要,将参数转换为数字。对于SET
值,转换操作会导致使用数值值。
通常,您可以使用FIND_IN_SET()
函数或LIKE
运算符来搜索SET
值:
mysql> SELECT * FROM *tbl_name* WHERE FIND_IN_SET('*value*',*set_col*)>0;
mysql> SELECT * FROM *tbl_name* WHERE *set_col* LIKE '%*value*%';
第一条语句查找包含value
集合成员的行。第二条类似,但不完全相同:它查找包含value
的任何地方的行,即使作为另一个集合成员的子字符串。
以下语句也是允许的:
mysql> SELECT * FROM *tbl_name* WHERE *set_col* & 1;
mysql> SELECT * FROM *tbl_name* WHERE *set_col* = '*val1*,*val2*';
这些语句中的第一个查找包含第一个集合成员的值。第二个查找精确匹配。对于第二种类型的比较要小心。将集合值与'*
val1*,*
val2*'
进行比较会产生不同的结果,与将值与'*
val2*,*
val1*'
进行比较不同。您应该按照它们在列定义中列出的顺序指定值。
要确定SET
列的所有可能值,请使用SHOW COLUMNS FROM *
tbl_name* LIKE *
set_col*
并解析输出的Type
列中的SET
定义。
在 C API 中,SET
值以字符串形式返回。有关使用结果集元数据将其与其他字符串区分开的信息,请参阅 C API 基本数据结构。
13.4 空间数据类型
13.4.1 空间数据类型
13.4.2 OpenGIS 几何模型
13.4.3 支持的空间数据格式
13.4.4 几何形态和有效性
13.4.5 空间参考系统支持
13.4.6 创建空间列
13.4.7 填充空间列
13.4.8 获取空间数据
13.4.9 优化空间分析
13.4.10 创建空间索引
13.4.11 使用空间索引
开放地理空间联盟(OGC)是一个由 250 多家公司、机构和大学参与开发公开可用的概念解决方案的国际联盟,这些解决方案可用于管理各种处理空间数据的应用程序。
开放地理空间联盟发布了OpenGIS®实施标准地理信息 - 简单要素访问 - 第 2 部分:SQL 选项,这是一份提出了几种概念性扩展 SQL RDBMS 以支持空间数据的文件。此规范可从 OGC 网站www.opengeospatial.org/standards/sfs
获取。
遵循 OGC 规范,MySQL 将空间扩展实现为带有几何类型的 SQL环境的子集。该术语指的是已扩展为一组几何类型的 SQL 环境。实现为具有几何类型的列的几何值的 SQL 列。规范描述了一组 SQL 几何类型,以及在这些类型上创建和分析几何值的函数。
MySQL 空间扩展使得可以生成、存储和分析地理要素:
-
用于表示空间值的数据类型
-
用于操作空间值的函数
-
空间索引以提高对空间列的访问时间
空间数据类型和函数可用于MyISAM
, InnoDB
, NDB
, 和 ARCHIVE
表。对于索引空间列,MyISAM
和 InnoDB
支持 SPATIAL
和非 SPATIAL
索引。其他存储引擎支持非 SPATIAL
索引,如 第 15.1.15 节,“CREATE INDEX 语句” 中所述。
地理要素 是世界上任何具有位置的事物。一个要素可以是:
-
一个实体。例如,一座山,一个池塘,一个城市。
-
一个空间。例如,城镇区,热带地区。
-
可定义的位置。例如,十字路口,作为两条街道交汇的特定地点。
一些文档使用术语地理空间特征来指代地理特征。
几何是指地理特征的另一个词。最初,几何一词指地球的测量。另一个含义来自制图学,指制图师用来绘制世界地图的几何特征。
这里讨论的术语视为同义词:地理特征,地理空间特征,特征或几何。最常用的术语是几何,定义为代表世界上任何具有位置的点或点的集合。
以下材料涵盖了这些主题:
-
MySQL 模型中实现的空间数据类型
-
OpenGIS 几何模型中空间扩展的基础
-
用于表示空间数据的数据格式
-
如何在 MySQL 中使用空间数据
-
用于空间数据的索引使用
-
MySQL 与 OpenGIS 规范的差异
有关操作空间数据的函数信息,请参见第 14.16 节,“空间分析函数”。
其他资源
这些标准对于 MySQL 实现空间操作很重要:
-
SQL/MM 第 3 部分:空间。
-
开放地理空间联盟发布了地理信息的 OpenGIS®实施标准,该文件提出了几种扩展 SQL RDBMS 以支持空间数据的概念方法。特别参见 Simple Feature Access - Part 1: Common Architecture 和 Simple Feature Access - Part 2: SQL Option。开放地理空间联盟(OGC)在
www.opengeospatial.org/
维护一个网站。规范可在www.opengeospatial.org/standards/sfs
上找到。其中包含与此材料相关的其他信息。 -
空间参考系统(SRS)定义的语法基于OpenGIS 实施规范:坐标转换服务,修订版 1.00,OGC 01-009,2001 年 1 月 12 日,第 7.2 节中定义的语法。该规范可在
www.opengeospatial.org/standards/ct
上找到。有关 MySQL 中 SRS 定义与该规范的差异,请参见第 15.1.19 节,“CREATE SPATIAL REFERENCE SYSTEM Statement”。
如果您对 MySQL 的空间扩展使用有疑问或担忧,可以在 GIS 论坛中讨论:forums.mysql.com/list.php?23
。
13.4.1 空间数据类型
原文:
dev.mysql.com/doc/refman/8.0/en/spatial-type-overview.html
MySQL 具有与 OpenGIS 类对应的空间数据类型。这些类型的基础在第 13.4.2 节,“OpenGIS 几何模型”中描述。
一些空间数据类型保存单个几何值:
-
GEOMETRY
-
POINT
-
LINESTRING
-
POLYGON
GEOMETRY
可以存储任何类型的几何值。其他单值类型(POINT
,LINESTRING
和POLYGON
)将其值限制为特定的几何类型。
其他空间数据类型保存值的集合:
-
MULTIPOINT
-
MULTILINESTRING
-
MULTIPOLYGON
-
GEOMETRYCOLLECTION
GEOMETRYCOLLECTION
可以存储任何类型的对象集合。其他集合类型(MULTIPOINT
,MULTILINESTRING
和MULTIPOLYGON
)将集合成员限制为具有特定几何类型的成员。
示例:要创建一个名为geom
的表,其中包含一个名为g
的列,可以存储任何几何类型的值,请使用以下语句:
CREATE TABLE geom (g GEOMETRY);
具有空间数据类型的列可以具有SRID
属性,以明确指示存储在列中的值的空间参考系统(SRS)。例如:
CREATE TABLE geom (
p POINT SRID 0,
g GEOMETRY NOT NULL SRID 4326
);
如果计划在列上创建SPATIAL
索引,则可以在具有特定 SRID 的列上创建SPATIAL
索引,因此,如果计划对列进行索引,请声明具有NOT NULL
和SRID
属性:
CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326);
InnoDB
表允许笛卡尔和地理 SRS 的SRID
值。MyISAM
表允许笛卡尔 SRS 的SRID
值。
SRID
属性使空间列受 SRID 限制,这具有以下影响:
-
该列只能包含具有给定 SRID 的值。尝试插入具有不同 SRID 的值会产生错误。
-
优化器可以在列上使用
SPATIAL
索引。请参见第 10.3.3 节,“SPATIAL 索引优化”。
没有SRID
属性的空间列不受 SRID 限制,并接受任何 SRID 的值。但是,在将列定义修改为包含SRID
属性之前,优化器无法在其上使用SPATIAL
索引,这可能需要首先修改列内容,以使所有值具有相同的 SRID。
有关如何在 MySQL 中使用空间数据类型的其他示例,请参见第 13.4.6 节,“创建空间列”。有关空间参考系统的信息,请参见第 13.4.5 节,“空间参考系统支持”。
13.4.2 OpenGIS 几何模型
原文:
dev.mysql.com/doc/refman/8.0/en/opengis-geometry-model.html
13.4.2.1 几何类层次结构
13.4.2.2 几何类
13.4.2.3 点类
13.4.2.4 曲线类
13.4.2.5 线串类
13.4.2.6 表面类
13.4.2.7 多边形类
13.4.2.8 几何集合类
13.4.2.9 多点类
13.4.2.10 多曲线类
13.4.2.11 多线串类
13.4.2.12 多表面类
13.4.2.13 多边形集合类
OGC 的带有几何类型的 SQL环境提出的几何类型集合基于OpenGIS 几何模型。在这个模型中,每个几何对象具有以下一般属性:
-
它与空间参考系统相关联,描述了对象定义的坐标空间。
-
它属于某些几何类。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-geometry-class-hierarchy.html
几何类层次结构
几何类定义如下层次结构:
-
Geometry
(不可实例化)-
Point
(可实例化) -
Curve
(不可实例化)-
LineString
(可实例化)-
Line
-
LinearRing
-
-
-
Surface
(不可实例化)Polygon
(可实例化)
-
GeometryCollection
(可实例化)-
MultiPoint
(可实例化) -
MultiCurve
(不可实例化)MultiLineString
(可实例化)
-
MultiSurface
(不可实例化)MultiPolygon
(可实例化)
-
-
不可能在不可实例化的类中创建对象。可以在可实例化的类中创建对象。所有类都有属性,可实例化的类也可能有断言(定义有效类实例的规则)。
Geometry
是基类。它是一个抽象类。Geometry
的可实例化子类限制为存在于二维坐标空间中的零、一和二维几何对象。所有可实例化的几何类都被定义为有效实例是拓扑闭合的(即,所有定义的几何包括其边界)。
基类Geometry
具有Point
、Curve
、Surface
和GeometryCollection
的子类:
-
Point
代表零维对象。 -
Curve
代表一维对象,具有子类LineString
,子子类Line
和LinearRing
。 -
Surface
设计用于二维对象,具有子类Polygon
。 -
GeometryCollection
具有专门的零、一和二维集合类,分别命名为MultiPoint
、MultiLineString
和MultiPolygon
,用于建模对应于Points
、LineStrings
和Polygons
的几何。MultiCurve
和MultiSurface
被引入为概括集合接口以处理Curves
和Surfaces
的抽象超类。
Geometry
、Curve
、Surface
、MultiCurve
和MultiSurface
被定义为不可实例化的类。它们为其子类定义了一组共同的方法,并且包含用于可扩展性的方法。
Point
、LineString
、Polygon
、GeometryCollection
、MultiPoint
、MultiLineString
和MultiPolygon
是可实例化的类。
13.4.2.2 几何类
Geometry
是层次结构的根类。它是一个不可实例化的类,但具有一些属性,描述了从任何Geometry
子类创建的所有几何值共有的属性。特定的子类具有自己的特定属性,稍后描述。
几何属性
几何值具有以下属性:
-
其类型。每个几何体属于层次结构中的可实例化类之一。
-
其SRID,或空间参考标识符。此值标识了描述几何对象定义的坐标空间的相关空间参考系统。
在 MySQL 中,SRID 值是与几何值关联的整数。可使用的最大 SRID 值为 2³²−1。如果给出一个更大的值,则只使用低 32 位。
SRID 0 表示一个无限的平面笛卡尔平面,其轴没有分配单位。为了确保 SRID 0 的行为,请使用 SRID 0 创建几何值。如果未指定 SRID,则 SRID 0 是新几何值的默认值。
对于多个几何值的计算,所有值必须具有相同的 SRID,否则会出错。
-
其在其空间参考系统中的坐标,表示为双精度(8 字节)数字。所有非空几何体至少包含一对(X,Y)坐标。空几何体不包含坐标。
坐标与 SRID 相关。例如,在不同的坐标系统中,两个对象之间的距离可能会有所不同,即使对象具有相同的坐标,因为平面坐标系统上的距离和大地测量系统(地球表面上的坐标)上的距离是不同的。
-
其内部,边界和外部。
每个几何体在空间中占据一定位置。几何体的外部是几何体未占据的所有空间。内部是几何体占据的空间。边界是几何体内部和外部之间的界面。
-
其MBR(最小外包矩形)或包络。这是由最小和最大(X,Y)坐标形成的边界几何体:
((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
-
值是简单还是非简单。类型为(
LineString
,MultiPoint
,MultiLineString
)的几何值要么是简单的,要么是非简单的。每种类型确定其自己的简单或非简单断言。 -
值是闭合还是未闭合。类型为(
LineString
,MultiString
)的几何值要么是闭合的,要么是未闭合的。每种类型确定其自己的闭合或未闭合断言。 -
该值是空还是非空。如果几何图形没有任何点,则为空。空几何图形的外部、内部和边界未定义(即,它们由
NULL
值表示)。空几何图形被定义为始终简单且面积为 0。 -
它的维度。一个几何图形可以具有维度为−1、0、1 或 2:
-
−1 代表空几何图形。
-
0 代表长度和面积均为零的几何图形。
-
1 代表具有非零长度和零面积的几何图形。
-
2 代表具有非零面积的几何图形。
Point
对象的维度为零。LineString
对象的维度为 1。Polygon
对象的维度为 2。MultiPoint
、MultiLineString
和MultiPolygon
对象的维度与它们所包含的元素的维度相同。 -
13.4.2.3 点类
一个Point
是表示坐标空间中单个位置的几何体。
Point
示例
-
想象一幅世界地图,上面标注着许多城市。一个
Point
对象可以代表每个城市。 -
在城市地图上,一个
Point
对象可以代表一个公交车站。
Point
属性
-
X 坐标值。
-
Y 坐标值。
-
Point
被定义为零维几何体。 -
一个
Point
的边界是空集。
13.4.2.4 Curve 类
一个Curve
是一维几何体,通常由一系列点表示。特定的Curve
子类定义了点之间的插值类型。Curve
是一个不可实例化的类。
Curve
属性
-
一个
Curve
具有其点的坐标。 -
一个
Curve
被定义为一维几何体。 -
如果一个
Curve
不通过同一点两次,则它是简单的,但如果起点和终点相同,则曲线仍然可以是简单的。 -
如果一个
Curve
的起点等于终点,则该Curve
是闭合的。 -
闭合
Curve
的边界为空。 -
非闭合
Curve
的边界由其两个端点组成。 -
一个简单且闭合的
Curve
是LinearRing
。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-linestring.html
13.4.2.5 LineString 类
一个LineString
是一个具有点之间线性插值的Curve
。
LineString
示例
-
在世界地图上,
LineString
对象可以表示河流。 -
在城市地图上,
LineString
对象可以表示街道。
LineString
属性
-
一个
LineString
由每对连续点定义的段的坐标组成。 -
如果一个
LineString
由恰好两个点组成,则它是一条Line
。 -
一个
LineString
如果既是封闭的又是简单的,就是一个LinearRing
。
13.4.2.6 Surface 类
一个Surface
是一个二维几何体。它是一个不可实例化的类。它唯一可实例化的子类是Polygon
。
Surface
属性
-
一个
Surface
被定义为一个二维几何体。 -
OpenGIS 规范将简单的
Surface
定义为一个几何体,由一个与单个外部边界和零个或多个内部边界相关联的“补丁”组成。 -
一个简单
Surface
的边界是与其外部和内部边界对应的一组闭合曲线。
13.4.2.7 Polygon 类
一个Polygon
是表示多边几何形状的平面Surface
。它由单个外部边界和零个或多个内部边界定义,其中每个内部边界定义了Polygon
中的一个孔。
Polygon
示例
- 在区域地图上,
Polygon
对象可以表示森林、区域等。
Polygon
断言
-
Polygon
的边界由一组LinearRing
对象(即,既简单又闭合的LineString
对象)组成,构成其外部和内部边界。 -
一个
Polygon
没有交叉的环。Polygon
边界中的环可能在一个Point
处相交,但只能作为切线。 -
一个
Polygon
没有线条、尖角或穿孔。 -
一个
Polygon
具有连通的内部点集。 -
一个
Polygon
可能有孔。带有孔的Polygon
的外部不是连通的。每个孔定义了外部的一个连通组件。
上述断言使Polygon
成为一个简单的几何体。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-geometrycollection.html
13.4.2.8 GeometryCollection 类
GeomCollection
是一个包含零个或多个任意类别几何体的集合几何体。
GeomCollection
和 GeometryCollection
是同义词,GeomCollection
是首选类型名称。
几何集合中的所有元素必须在相同的空间参考系统中(即在相同的坐标系统中)。对于几何集合的元素没有其他约束,尽管下面描述的 GeomCollection
的子类可能会限制成员资格。限制可能基于:
-
元素类型(例如,
MultiPoint
可能只包含Point
元素) -
维度
-
元素之间空间重叠程度的约束
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-multipoint.html
13.4.2.9 MultiPoint 类
一个MultiPoint
是由Point
元素组成的几何集合。这些点没有以任何方式连接或排序。
MultiPoint
示例
-
在世界地图上,一个
MultiPoint
可以代表一串小岛。 -
在城市地图上,一个
MultiPoint
可以代表售票处的出口。
MultiPoint
属性
-
一个
MultiPoint
是一个零维几何体。 -
如果一个
MultiPoint
的两个Point
值不相等(具有相同的坐标值),那么它就是简单的。 -
一个
MultiPoint
的边界是空集。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-multicurve.html
13.4.2.10 MultiCurve 类
MultiCurve
是由 Curve
元素组成的几何集合。MultiCurve
是一个不可实例化的类。
MultiCurve
属性
-
MultiCurve
是一维几何体。 -
当且仅当
MultiCurve
的所有元素都是简单的时,MultiCurve
才是简单的;任何两个元素之间的唯一交点发生在这两个元素的边界上。 -
通过应用“模 2 并集规则”(也称为“奇偶规则”)可以获得
MultiCurve
边界:如果一个点在奇数个Curve
元素的边界上,则它在MultiCurve
的边界上。 -
如果
MultiCurve
的所有元素都是闭合的,则MultiCurve
是闭合的。 -
闭合
MultiCurve
的边界始终为空。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-multilinestring.html
13.4.2.11 MultiLineString 类
一个MultiLineString
是由LineString
元素组成的MultiCurve
几何集合。
MultiLineString
示例
- 在区域地图上,一个
MultiLineString
可以代表一个河流系统或者高速公路系统。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-multisurface.html
13.4.2.12 多表面类
一个MultiSurface
是由表面元素组成的几何集合。MultiSurface
是一个不可实例化的类。它唯一可实例化的子类是MultiPolygon
。
MultiSurface
断言
-
MultiSurface
内的表面没有相交的内部。 -
MultiSurface
内的表面的边界最多在有限数量的点处相交。
原文:
dev.mysql.com/doc/refman/8.0/en/gis-class-multipolygon.html
13.4.2.13 MultiPolygon 类
一个MultiPolygon
是由Polygon
元素组成的MultiSurface
对象。
MultiPolygon
示例
- 在区域地图上,一个
MultiPolygon
可以代表一个湖泊系统。
MultiPolygon
断言
-
一个
MultiPolygon
没有两个内部相交的Polygon
元素。 -
一个
MultiPolygon
没有两个相交的Polygon
元素(相交也被前一个断言禁止),或者在无限多点处接触。 -
一个
MultiPolygon
不能有切线、尖点或穿孔。一个MultiPolygon
是一个规则的、闭合的点集。 -
一个具有多个
Polygon
的MultiPolygon
具有不连通的内部。MultiPolygon
内部的连通分量数量等于MultiPolygon
中的Polygon
值数量。
MultiPolygon
属性
-
一个
MultiPolygon
是一个二维几何体。 -
一个
MultiPolygon
的边界是一组闭合曲线(LineString
值),对应于其Polygon
元素的边界。 -
MultiPolygon
边界中的每个Curve
都在一个Polygon
元素的边界中。 -
每个
Polygon
元素边界中的每个Curve
都在MultiPolygon
的边界中。
13.4.3 支持的空间数据格式
用于在查询中表示几何对象的两种标准空间数据格式:
-
Well-Known Text (WKT)格式
-
Well-Known Binary (WKB)格式
在内部,MySQL 以一种与 WKT 或 WKB 格式不完全相同的格式存储几何值(内部格式类似于 WKB,但具有用于指示 SRID 的初始 4 个字节)。
有函数可用于在不同数据格式之间转换;参见第 14.16.6 节,“几何格式转换函数”。
以下各节描述了 MySQL 使用的空间数据格式:
-
Well-Known Text (WKT) Format Format")
-
Well-Known Binary (WKB) Format Format")
-
Internal Geometry Storage Format
Well-Known Text (WKT)格式
几何值的 Well-Known Text (WKT)表示设计用于以 ASCII 形式交换几何数据。OpenGIS 规范提供了一个 Backus-Naur 语法,指定了编写 WKT 值的正式生成规则(参见第 13.4 节,“空间数据类型”)。
几何对象的 WKT 表示示例:
-
一个
Point
:POINT(15 20)
点坐标未用逗号分隔。这与 SQL
Point()
函数的语法不同,后者要求坐标之间有逗号。请注意使用适合给定空间操作上下文的语法。例如,以下语句都使用ST_X()
从Point
对象中提取 X 坐标。第一个直接使用Point()
函数生成对象。第二个使用转换为Point
的 WKT 表示,使用ST_GeomFromText()
。mysql> SELECT ST_X(Point(15, 20)); +---------------------+ | ST_X(POINT(15, 20)) | +---------------------+ | 15 | +---------------------+ mysql> SELECT ST_X(ST_GeomFromText('POINT(15 20)')); +---------------------------------------+ | ST_X(ST_GeomFromText('POINT(15 20)')) | +---------------------------------------+ | 15 | +---------------------------------------+
-
具有四个点的
LineString
:LINESTRING(0 0, 10 10, 20 25, 50 60)
点坐标对由逗号分隔。
-
具有一个外环和一个内环的
Polygon
:POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))
-
具有三个
Point
值的MultiPoint
:MULTIPOINT(0 0, 20 20, 60 60)
接受
MultiPoint
值的 WKT 格式表示的空间函数,如ST_MPointFromText()
和ST_GeomFromText()
,允许值内的单个点被括号括起来。例如,以下两个函数调用都是有效的:ST_MPointFromText('MULTIPOINT (1 1, 2 2, 3 3)') ST_MPointFromText('MULTIPOINT ((1 1), (2 2), (3 3))')
-
一个具有两个
LineString
值的MultiLineString
:MULTILINESTRING((10 10, 20 20), (15 15, 30 15))
-
具有��个
Polygon
值的MultiPolygon
:MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((5 5,7 5,7 7,5 7, 5 5)))
-
由两个
Point
值和一个LineString
组成的GeometryCollection
:GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))
熟知二进制(WKB)格式
几何值的熟知二进制(WKB)表示用于以二进制流交换几何数据,表示为包含几何 WKB 信息的 BLOB
值。该格式由 OpenGIS 规范定义(请参阅第 13.4 节,“空间数据类型”)。它还在 ISO SQL/MM 第 3 部分:空间标准中定义。
WKB 使用 1 字节无符号整数、4 字节无符号整数和 8 字节双精度数(IEEE 754 格式)。一个字节是八位。
例如,与 POINT(1 -1)
对应的 WKB 值由以下 21 个字节序列组成,每个字节由两个十六进制数字表示:
0101000000000000000000F03F000000000000F0BF
该序列由下表中显示的组件组成。
表 13.2 WKB 组件示例
组件 | 大小 | 值 |
---|---|---|
字节顺序 | 1 字节 | 01 |
WKB 类型 | 4 字节 | 01000000 |
X 坐标 | 8 字节 | 000000000000F03F |
Y 坐标 | 8 字节 | 000000000000F0BF |
组件表示如下:
-
字节顺序指示符为 1 或 0,表示小端或大端存储。小端和大端字节顺序也被称为网络数据表示(NDR)和外部数据表示(XDR)。
-
WKB 类型是指示几何类型的代码。MySQL 使用值从 1 到 7 来表示
Point
、LineString
、Polygon
、MultiPoint
、MultiLineString
、MultiPolygon
和GeometryCollection
。 -
Point
值具有 X 和 Y 坐标,每个坐标表示为双精度值。
更复杂的几何值的 WKB 值具有更复杂的数据结构,详细信息请参阅 OpenGIS 规范。
内部几何存储格式
MySQL 使用 4 个字节来指示 SRID,然后是值的 WKB 表示。有关 WKB 格式的描述,请参阅熟知二进制(WKB)格式。
对于 WKB 部分,这些是适用于 MySQL 的特定考虑因素:
-
字节顺序指示符字节为 1,因为 MySQL 将几何值存储为小端值。
-
MySQL 支持
Point
、LineString
、Polygon
、MultiPoint
、MultiLineString
、MultiPolygon
和GeometryCollection
几何类型。不支持其他几何类型。 -
只有
GeometryCollection
可以为空。这样的值存储为 0 元素。 -
多边形环可以指定顺时针和逆时针。MySQL 在读取数据时会自动翻转环。
笛卡尔坐标以空间参考系统的长度单位存储,X 值在 X 坐标中,Y 值在 Y 坐标中。轴方向由空间参考系统指定。
地理坐标以空间参考系统的角度单位存储,经度在 X 坐标中,纬度在 Y 坐标中。轴方向和子午线由空间参考系统指定。
LENGTH()
函数返回存储值所需的字节空间。例如:
mysql> SET @g = ST_GeomFromText('POINT(1 -1)');
mysql> SELECT LENGTH(@g);
+------------+
| LENGTH(@g) |
+------------+
| 25 |
+------------+
mysql> SELECT HEX(@g);
+----------------------------------------------------+
| HEX(@g) |
+----------------------------------------------------+
| 000000000101000000000000000000F03F000000000000F0BF |
+----------------------------------------------------+
值长度为 25 个字节,由以下组件组成(如从十六进制值中可以看出):
-
4 个字节用于整数 SRID(0)
-
1 个字节用于整数字节顺序(1 = 小端)
-
4 个字节用于整数类型信息(1 =
Point
) -
8 个字节用于双精度 X 坐标(1)
-
8 个字节用于双精度 Y 坐标(−1)
13.4.4 几何体的良好形成性和有效性
原文:
dev.mysql.com/doc/refman/8.0/en/geometry-well-formedness-validity.html
对于几何值,MySQL 区分了语法上良好形成和几何有效的概念。
如果几何体满足这个(不全面)列表中的条件,那么它在语法上是良好形成的:
-
线串至少有两个点
-
多边形至少有一个环
-
多边形环是封闭的(第一个和最后一个点相同)
-
多边形环至少有 4 个点(最小多边形是一个三角形,第一个和最后一个点相同)
-
集合不为空(除了
GeometryCollection
)
如果几何体在语法上是良好形成的并满足这个(不全面)列表中的条件,那么它在几何上是有效的:
-
多边形不会自相交
-
多边形内部环在外部环内
-
多边形不会有重叠的多边形
如果几何体在语法上不是良好形成的,则空间函数会失败。解析 WKT 或 WKB 值的空间导入函数会对尝试创建不在语法上良好形成的几何体的操作引发错误。对于尝试将几何体存储到表中的操作也会检查语法上的良好形成性。
允许插入、选择和更新几何上无效的几何体,但它们必须在语法上是良好形成的。由于计算开销,MySQL 不会明确检查几何有效性。空间计算可能会检测到一些无效几何体并引发错误,但也可能在不检测到无效性的情况下返回未定义的结果。需要几何有效性的应用程序应使用 ST_IsValid()
函数进行检查。
13.4.5 空间参考系统支持
原文:
dev.mysql.com/doc/refman/8.0/en/spatial-reference-systems.html
空间数据的空间参考系统(SRS)是用于地理位置的基于坐标的系统。
有不同类型的空间参考系统:
-
投影 SRS 是将地球投影到平面表面的投影;也就是说,是一个平面地图。例如,一个位于地球仪内部的灯泡照射到包围地球的纸筒上,将地图投影到纸上。结果是地理参考:每个点映射到地球上的一个位置。该平面上的坐标系统是笛卡尔坐标系,使用长度单位(米、英尺等),而不是经度和纬度的度数。
在这种情况下,地球是椭球体;也就是说,是扁平的球体。地球在南北轴上比东西轴短一点,所以稍微扁平的球体更正确,但完美的球体可以进行更快的计算。
-
地理 SRS 是表示椭球上经度-纬度(或纬度-经度)坐标的非投影 SRS,使用任何角度单位。
-
MySQL 中由 SRID 0 表示的 SRS 代表一个无限的平面笛卡尔平面,其轴没有分配单位。与投影 SRS 不同,它没有地理参考,也不一定代表地球。它是一个可以用于任何事物的抽象平面。SRID 0 是 MySQL 中空间数据的默认 SRID。
MySQL 在数据字典mysql.st_spatial_reference_systems
表中维护有关空间数据可用空间参考系统的信息,该表可以存储投影和地理 SRS 的条目。这个数据字典表是不可见的,但 SRS 条目内容可以通过INFORMATION_SCHEMA
ST_SPATIAL_REFERENCE_SYSTEMS
表获得,该表作为mysql.st_spatial_reference_systems
上的视图实现(参见 Section 28.3.36, “INFORMATION_SCHEMA ST_SPATIAL_REFERENCE_SYSTEMS 表”)。
以下示例展示了 SRS 条目的外观:
mysql> SELECT *
FROM INFORMATION_SCHEMA.ST_SPATIAL_REFERENCE_SYSTEMS
WHERE SRS_ID = 4326\G
*************************** 1\. row ***************************
SRS_NAME: WGS 84
SRS_ID: 4326
ORGANIZATION: EPSG
ORGANIZATION_COORDSYS_ID: 4326
DEFINITION: GEOGCS["WGS 84",DATUM["World Geodetic System 1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
UNIT["degree",0.017453292519943278,
AUTHORITY["EPSG","9122"]],
AXIS["Lat",NORTH],AXIS["Long",EAST],
AUTHORITY["EPSG","4326"]]
DESCRIPTION:
本条目描述了用于 GPS 系统的 SRS。它的名称(SRS_NAME
)是 WGS 84,ID(SRS_ID
)是 4326,这是欧洲石油勘探集团(EPSG)使用的 ID。
DEFINITION
列中的 SRS 定义是 WKT 值,表示为开放地理空间联盟文档OGC 12-063r5中指定的形式。
SRS_ID
值代表与几何值的 SRID 相同类型的值,或作为空间函数的 SRID 参数传递。SRID 0(无单位的笛卡尔平面)是特殊的。它始终是合法的空间参考系统 ID,并且可以在依赖于 SRID 值的空间数据的任何计算中使用。
对于多个几何值的计算,所有值必须具有相同的 SRID,否则会出错。
当 GIS 函数需要定义时,SRS 定义会按需解析。解析后的定义存储在数据字典缓存中,以便重复使用,并避免为每个需要 SRS 信息的语句产生解析开销。
为了使数据字典中存储的 SRS 条目可以进行操作,MySQL 提供了以下 SQL 语句:
-
CREATE SPATIAL REFERENCE SYSTEM
: 查看第 15.1.19 节,“CREATE SPATIAL REFERENCE SYSTEM Statement”。该语句的描述包括有关 SRS 组件的附加信息。 -
DROP SPATIAL REFERENCE SYSTEM
: 查看第 15.1.31 节,“DROP SPATIAL REFERENCE SYSTEM Statement”。
13.4.6 创建空间列
原文:
dev.mysql.com/doc/refman/8.0/en/creating-spatial-columns.html
MySQL 提供了一种标准方法来为几何类型创建空间列,例如,使用CREATE TABLE
或ALTER TABLE
。空间列支持MyISAM
、InnoDB
、NDB
和ARCHIVE
表。另请参阅有关在第 13.4.10 节,“创建空间索引”下的空间索引的注意事项。
具有空间数据类型的列可以具有 SRID 属性,以明确指示存储在列中的值的空间参考系统(SRS)。有关 SRID 受限列的影响,请参见第 13.4.1 节,“空间数据类型”。
-
使用
CREATE TABLE
语句创建具有空间列的表:CREATE TABLE geom (g GEOMETRY);
-
使用
ALTER TABLE
语句向现有表添加或删除空间列:ALTER TABLE geom ADD pt POINT; ALTER TABLE geom DROP pt;
13.4.7 填充空间列
原文:
dev.mysql.com/doc/refman/8.0/en/populating-spatial-columns.html
在创建空间列之后,您可以用空间数据填充它们。
值应存储在内部几何格式中,但您可以将它们从 Well-Known Text(WKT)或 Well-Known Binary(WKB)格式转换为该格式。以下示例演示了如何通过将 WKT 值转换为内部几何格式将几何值插入表中:
-
直接在
INSERT
语句中执行转换:INSERT INTO geom VALUES (ST_GeomFromText('POINT(1 1)')); SET @g = 'POINT(1 1)'; INSERT INTO geom VALUES (ST_GeomFromText(@g));
-
在
INSERT
之前执行转换:SET @g = ST_GeomFromText('POINT(1 1)'); INSERT INTO geom VALUES (@g);
以下示例将更复杂的几何形状插入表中:
SET @g = 'LINESTRING(0 0,1 1,2 2)';
INSERT INTO geom VALUES (ST_GeomFromText(@g));
SET @g = 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))';
INSERT INTO geom VALUES (ST_GeomFromText(@g));
SET @g =
'GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
INSERT INTO geom VALUES (ST_GeomFromText(@g));
前面的示例使用ST_GeomFromText()
创建几何值。您还可以使用特定类型的函数:
SET @g = 'POINT(1 1)';
INSERT INTO geom VALUES (ST_PointFromText(@g));
SET @g = 'LINESTRING(0 0,1 1,2 2)';
INSERT INTO geom VALUES (ST_LineStringFromText(@g));
SET @g = 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))';
INSERT INTO geom VALUES (ST_PolygonFromText(@g));
SET @g =
'GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
INSERT INTO geom VALUES (ST_GeomCollFromText(@g));
想要使用 WKB 表示几何值的客户端应用程序负责向服务器发送正确形成的 WKB 查询。有几种方法可以满足此要求。例如:
-
插入一个带有十六进制字面值语法的
POINT(1 1)
值:INSERT INTO geom VALUES (ST_GeomFromWKB(X'0101000000000000000000F03F000000000000F03F'));
-
ODBC 应用程序可以发送 WKB 表示,将其绑定到使用
BLOB
类型的参数的占位符:INSERT INTO geom VALUES (ST_GeomFromWKB(?))
其他编程接口可能支持类似的占位符机制。
-
在 C 程序中,您可以使用
mysql_real_escape_string_quote()
转义二进制值,并将结果包含在发送到服务器的查询字符串中。请参见 mysql_real_escape_string_quote()。
13.4.8 获取空间数据
原文:
dev.mysql.com/doc/refman/8.0/en/fetching-spatial-data.html
存储在表中的几何值可以以内部格式获取。您还可以将它们转换为 WKT 或 WKB 格式。
-
获取内部格式的空间数据:
使用内部格式获取几何值在表与表之间的转移中可能很有用:
CREATE TABLE geom2 (g GEOMETRY) SELECT g FROM geom;
-
获取 WKT 格式的空间数据:
ST_AsText()
函数将几何从内部格式转换为 WKT 字符串。SELECT ST_AsText(g) FROM geom;
-
获取 WKB 格式的空间数据:
ST_AsBinary()
函数将几何从内部格式转换为包含 WKB 值的BLOB
。SELECT ST_AsBinary(g) FROM geom;
13.4.9 优化空间分析
原文:
dev.mysql.com/doc/refman/8.0/en/optimizing-spatial-analysis.html
对于MyISAM
和InnoDB
表,包含空间数据的列中的搜索操作可以使用SPATIAL
索引进行优化。最典型的操作包括:
-
点查询,搜索包含给定点的所有对象
-
区域查询,搜索与给定区域重叠的所有对象
MySQL 在空间列上使用具有二次分裂的 R-Tree来构建SPATIAL
索引。SPATIAL
索引是使用几何图形的最小外接矩形(MBR)构建的。对于大多数几何图形,MBR 是一个围绕几何图形的最小矩形。对于水平或垂直线串,MBR 是一个退化为线串的矩形。对于点,MBR 是一个退化为点的矩形。
也可以在空间列上创建普通索引。在非SPATIAL
索引中,必须为除POINT
列之外的任何空间列声明前缀。
MyISAM
和InnoDB
都支持SPATIAL
和非SPATIAL
索引。其他存储引擎支持非SPATIAL
索引,如第 15.1.15 节,“CREATE INDEX 语句”中所述。
13.4.10 创建空间索引
原文:
dev.mysql.com/doc/refman/8.0/en/creating-spatial-indexes.html
对于InnoDB
和MyISAM
表,MySQL 可以使用类似于创建常规索引的语法来创建空间索引,但使用SPATIAL
关键字。空间索引中的列必须声明为NOT NULL
。以下示例演示了如何创建空间索引:
-
使用
CREATE TABLE
:CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326, SPATIAL INDEX(g));
-
使用
ALTER TABLE
:CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326); ALTER TABLE geom ADD SPATIAL INDEX(g);
-
使用
CREATE INDEX
:CREATE TABLE geom (g GEOMETRY NOT NULL SRID 4326); CREATE SPATIAL INDEX g ON geom (g);
SPATIAL INDEX
创建一个 R 树索引。对于支持对空间列进行非空间索引的存储引擎,引擎会创建一个 B 树索引。对空间值创建 B 树索引对于精确值查找很有用,但不适用于范围扫描。
优化器可以使用在受 SRID 限制的列上定义的空间索引。有关更多信息,请参见第 13.4.1 节,“空间数据类型”和第 10.3.3 节,“空间索引优化”。
有关在空间列上创建索引的更多信息,请参见第 15.1.15 节,“CREATE INDEX Statement”。
要删除空间索引,请使用ALTER TABLE
或DROP INDEX
:
-
使用
ALTER TABLE
:ALTER TABLE geom DROP INDEX g;
-
使用
DROP INDEX
:DROP INDEX g ON geom;
例如:假设一个表geom
包含超过 32,000 个几何图形,这些图形存储在类型为GEOMETRY
的列g
中。该表还有一个AUTO_INCREMENT
列fid
用于存储对象 ID 值。
mysql> DESCRIBE geom;
+-------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+----------------+
| fid | int(11) | | PRI | NULL | auto_increment |
| g | geometry | | | | |
+-------+----------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> SELECT COUNT(*) FROM geom;
+----------+
| count(*) |
+----------+
| 32376 |
+----------+
1 row in set (0.00 sec)
要在列g
上添加空间索引,请使用以下语句:
mysql> ALTER TABLE geom ADD SPATIAL INDEX(g);
Query OK, 32376 rows affected (4.05 sec)
Records: 32376 Duplicates: 0 Warnings: 0
13.4.11 使用空间索引
原文:
dev.mysql.com/doc/refman/8.0/en/using-spatial-indexes.html
优化器会检查是否可以利用可用的空间索引来搜索使用WHERE
子句中的函数如MBRContains()
或MBRWithin()
的查询。以下查询找到所有在给定矩形内的对象:
mysql> SET @poly =
-> 'Polygon((30000 15000,
31000 15000,
31000 16000,
30000 16000,
30000 15000))';
mysql> SELECT fid,ST_AsText(g) FROM geom WHERE
-> MBRContains(ST_GeomFromText(@poly),g);
+-----+---------------------------------------------------------------+
| fid | ST_AsText(g) |
+-----+---------------------------------------------------------------+
| 21 | LINESTRING(30350.4 15828.8,30350.6 15845,30333.8 15845,30 ... |
| 22 | LINESTRING(30350.6 15871.4,30350.6 15887.8,30334 15887.8, ... |
| 23 | LINESTRING(30350.6 15914.2,30350.6 15930.4,30334 15930.4, ... |
| 24 | LINESTRING(30290.2 15823,30290.2 15839.4,30273.4 15839.4, ... |
| 25 | LINESTRING(30291.4 15866.2,30291.6 15882.4,30274.8 15882\. ... |
| 26 | LINESTRING(30291.6 15918.2,30291.6 15934.4,30275 15934.4, ... |
| 249 | LINESTRING(30337.8 15938.6,30337.8 15946.8,30320.4 15946\. ... |
| 1 | LINESTRING(30250.4 15129.2,30248.8 15138.4,30238.2 15136\. ... |
| 2 | LINESTRING(30220.2 15122.8,30217.2 15137.8,30207.6 15136, ... |
| 3 | LINESTRING(30179 15114.4,30176.6 15129.4,30167 15128,3016 ... |
| 4 | LINESTRING(30155.2 15121.4,30140.4 15118.6,30142 15109,30 ... |
| 5 | LINESTRING(30192.4 15085,30177.6 15082.2,30179.2 15072.4, ... |
| 6 | LINESTRING(30244 15087,30229 15086.2,30229.4 15076.4,3024 ... |
| 7 | LINESTRING(30200.6 15059.4,30185.6 15058.6,30186 15048.8, ... |
| 10 | LINESTRING(30179.6 15017.8,30181 15002.8,30190.8 15003.6, ... |
| 11 | LINESTRING(30154.2 15000.4,30168.6 15004.8,30166 15014.2, ... |
| 13 | LINESTRING(30105 15065.8,30108.4 15050.8,30118 15053,3011 ... |
| 154 | LINESTRING(30276.2 15143.8,30261.4 15141,30263 15131.4,30 ... |
| 155 | LINESTRING(30269.8 15084,30269.4 15093.4,30258.6 15093,30 ... |
| 157 | LINESTRING(30128.2 15011,30113.2 15010.2,30113.6 15000.4, ... |
+-----+---------------------------------------------------------------+
20 rows in set (0.00 sec)
使用EXPLAIN
来检查这个查询的执行方式:
mysql> SET @poly =
-> 'Polygon((30000 15000,
31000 15000,
31000 16000,
30000 16000,
30000 15000))';
mysql> EXPLAIN SELECT fid,ST_AsText(g) FROM geom WHERE
-> MBRContains(ST_GeomFromText(@poly),g)\G
*************************** 1\. row ***************************
id: 1
select_type: SIMPLE
table: geom
type: range
possible_keys: g
key: g
key_len: 32
ref: NULL
rows: 50
Extra: Using where 1 row in set (0.00 sec)
检查没有空间索引会发生什么:
mysql> SET @poly =
-> 'Polygon((30000 15000,
31000 15000,
31000 16000,
30000 16000,
30000 15000))';
mysql> EXPLAIN SELECT fid,ST_AsText(g) FROM g IGNORE INDEX (g) WHERE
-> MBRContains(ST_GeomFromText(@poly),g)\G
*************************** 1\. row ***************************
id: 1
select_type: SIMPLE
table: geom
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 32376
Extra: Using where 1 row in set (0.00 sec)
在没有空间索引的情况下执行SELECT
语句会得到相同的结果,但执行时间从 0.00 秒上升到 0.46 秒:
mysql> SET @poly =
-> 'Polygon((30000 15000,
31000 15000,
31000 16000,
30000 16000,
30000 15000))';
mysql> SELECT fid,ST_AsText(g) FROM geom IGNORE INDEX (g) WHERE
-> MBRContains(ST_GeomFromText(@poly),g);
+-----+---------------------------------------------------------------+
| fid | ST_AsText(g) |
+-----+---------------------------------------------------------------+
| 1 | LINESTRING(30250.4 15129.2,30248.8 15138.4,30238.2 15136\. ... |
| 2 | LINESTRING(30220.2 15122.8,30217.2 15137.8,30207.6 15136, ... |
| 3 | LINESTRING(30179 15114.4,30176.6 15129.4,30167 15128,3016 ... |
| 4 | LINESTRING(30155.2 15121.4,30140.4 15118.6,30142 15109,30 ... |
| 5 | LINESTRING(30192.4 15085,30177.6 15082.2,30179.2 15072.4, ... |
| 6 | LINESTRING(30244 15087,30229 15086.2,30229.4 15076.4,3024 ... |
| 7 | LINESTRING(30200.6 15059.4,30185.6 15058.6,30186 15048.8, ... |
| 10 | LINESTRING(30179.6 15017.8,30181 15002.8,30190.8 15003.6, ... |
| 11 | LINESTRING(30154.2 15000.4,30168.6 15004.8,30166 15014.2, ... |
| 13 | LINESTRING(30105 15065.8,30108.4 15050.8,30118 15053,3011 ... |
| 21 | LINESTRING(30350.4 15828.8,30350.6 15845,30333.8 15845,30 ... |
| 22 | LINESTRING(30350.6 15871.4,30350.6 15887.8,30334 15887.8, ... |
| 23 | LINESTRING(30350.6 15914.2,30350.6 15930.4,30334 15930.4, ... |
| 24 | LINESTRING(30290.2 15823,30290.2 15839.4,30273.4 15839.4, ... |
| 25 | LINESTRING(30291.4 15866.2,30291.6 15882.4,30274.8 15882\. ... |
| 26 | LINESTRING(30291.6 15918.2,30291.6 15934.4,30275 15934.4, ... |
| 154 | LINESTRING(30276.2 15143.8,30261.4 15141,30263 15131.4,30 ... |
| 155 | LINESTRING(30269.8 15084,30269.4 15093.4,30258.6 15093,30 ... |
| 157 | LINESTRING(30128.2 15011,30113.2 15010.2,30113.6 15000.4, ... |
| 249 | LINESTRING(30337.8 15938.6,30337.8 15946.8,30320.4 15946\. ... |
+-----+---------------------------------------------------------------+
20 rows in set (0.46 sec)
13.5 JSON 数据类型
-
创建 JSON 值
-
JSON 值的规范化、合并和自动包装
-
搜索和修改 JSON 值
-
JSON 路径语法
-
JSON 值的比较和排序
-
JSON 和非 JSON 值之间的转换
-
JSON 值的聚合
MySQL 支持由RFC 7159定义的本机JSON
数据类型,可实现对 JSON(JavaScript 对象表示)文档中数据的高效访问。JSON
数据类型相对于在字符串列中存储 JSON 格式字符串具有以下优势:
-
存储在
JSON
列中的 JSON 文档的自动验证。无效文档会产生错误。 -
优化的存储格式。存储在
JSON
列中的 JSON 文档会转换为内部格式,以便快速读取文档元素。当服务器后续必须从此二进制格式中读取存储的 JSON 值时,无需从文本表示中解析值。二进制格式被设计为使服务器能够直接通过键或数组索引查找子对象或嵌套值,而无需在文档中读取它们之前或之后的所有值。
MySQL 8.0 还支持RFC 7396中定义的JSON 合并补丁格式,使用JSON_MERGE_PATCH()
函数。请参阅此函数的描述,以及 JSON 值的规范化、合并和自动包装,获取示例和更多信息。
注意
本讨论中使用单调字体的JSON
表示特定的 JSON 数据类型,JSON
使用常规字体表示一般的 JSON 数据。
存储 JSON
文档所需的空间大致与 LONGBLOB
或 LONGTEXT
相同;有关更多信息,请参见 第 13.7 节,“数据类型存储要求”。重要的是要记住,存储在 JSON
列中的任何 JSON 文档的大小受限于 max_allowed_packet
系统变量的值。(当服务器在内存中内部操作 JSON 值时,它可以比这个值更大;限制适用于服务器存储它时。)您可以使用 JSON_STORAGE_SIZE()
函数获取存储 JSON 文档所需空间的量;请注意,对于 JSON
列,存储大小——因此此函数返回的值——是在对其执行的任何部分更新之前使用的列的大小(请参见本节后面关于 JSON 部分更新优化的讨论)。
在 MySQL 8.0.13 之前,JSON
列不能有非NULL
默认值。
除了 JSON
数据类型外,还提供了一组 SQL 函数,用于对 JSON 值进行操作,如创建、操作和搜索。以下讨论展示了这些操作的示例。有关各个函数的详细信息,请参见 第 14.17 节,“JSON 函数”。
还提供了一组用于操作 GeoJSON 值的空间函数。请参见 第 14.16.11 节,“空间 GeoJSON 函数”。
JSON
列,就像其他二进制类型的列一样,不能直接索引;相反,您可以在生成的列上创建索引,从 JSON
列中提取标量值。有关详细示例,请参见 在生成的列上创建索引以提供 JSON 列索引。
MySQL 优化器还会查找与匹配 JSON 表达式的虚拟列上的兼容索引。
在 MySQL 8.0.17 及更高版本中,InnoDB
存储引擎支持对 JSON 数组进行多值索引。请参见 多值索引。
MySQL NDB Cluster 8.0 支持 JSON
列和 MySQL JSON 函数,包括在从 JSON
列生成的列上创建索引,作为无法对 JSON
列进行索引的解决方法。每个 NDB
表支持最多 3 个 JSON
列。
JSON 值的部分更新
在 MySQL 8.0 中,优化器可以对JSON
列执行部分、原地更新,而不是删除旧文档并将新文档完全写入列。此优化可用于满足以下条件的更新:
-
正在更新的列被声明为
JSON
。 -
UPDATE
语句使用三个函数中的任何一个JSON_SET()
,JSON_REPLACE()
, 或JSON_REMOVE()
来更新列。不能像直接赋值列值(例如,UPDATE mytable SET jcol = '{"a": 10, "b": 25}'
)这样进行部分更新。在单个
UPDATE
语句中更新多个JSON
列可以通过这种方式进行优化;MySQL 可以仅对使用刚才列出的三个函数更新值的列进行部分更新。 -
输入列和目标列必须是同一列;不能像
UPDATE mytable SET jcol1 = JSON_SET(jcol2, '$.a', 100)
这样进行部分更新。更新可以使用前一项中列出的任何函数的嵌套调用,以任何组合,只要输入和目标列是相同的。
-
所有更改都用新值替换现有数组或对象值,并且不向父对象或数组添加任何新元素。
-
被替换的值必须至少和替换值一样大。换句话说,新值不能比旧值更大。
当之前的部分更新留下足够空间容纳更大值时,可能会有一个例外。您可以使用函数
JSON_STORAGE_FREE()
查看通过对JSON
列进行任何部分更新而释放了多少空间。
可以使用紧凑格式将这种部分更新写入二进制日志,以节省空间;可以通过将binlog_row_value_options
系统变量设置为PARTIAL_JSON
来启用此功能。
重要的是要区分表中存储的JSON
列值的部分更新与将行的部分更新写入二进制日志。当前面列表中的最后两个条件中的任一条件(或两者)不满足但其他条件满足时,可以将JSON
列的完整更新记录为部分更新。
参见binlog_row_value_options
的描述。
接下来的几节提供有关创建和操作 JSON 值的基本信息。
创建 JSON 值
JSON 数组包含由逗号分隔并在[
和]
字符内包围的值列表:
["abc", 10, null, true, false]
JSON 对象包含一组由逗号分隔并在{
和}
字符内封装的键值对:
{"k1": "value", "k2": 10}
正如示例所示,JSON 数组和对象可以包含作为字符串或数字的标量值,JSON null 字面值,或 JSON 布尔 true 或 false 字面值。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 提供的许多用于此目的的函数(请参阅第 14.17.2 节,“创建 JSON 值的函数”)以及通过将其他类型的值转换为JSON
类型使用CAST(*
value* AS JSON)
(请参阅在 JSON 和非 JSON 值之间转换)来获取 JSON 值。接下来的几段描述了 MySQL 如何处理提供的 JSON 值作为输入。
在 MySQL 中,JSON 值被写为字符串。MySQL 解析任何在需要 JSON 值的上下文中使用的字符串,并在其无效为 JSON 时产生错误。这些上下文包括将值插入具有JSON
数据类型的列中以及将参数传递给期望 JSON 值的函数(通常在 MySQL JSON 函数文档中显示为json_doc
或json_val
),如以下示例所示:
-
尝试将值插入
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,'.
在这种错误消息中,“在位置
N
处”表示基于 0 的位置,但应该被视为值中实际问题发生位置的粗略指示。 -
[
JSON_TYPE()
函数期望一个 JSON 参数并尝试将其解析为 JSON 值。如果有效则返回该值的 JSON 类型,否则产生错误:mysql> SELECT JSON_TYPE('["a", "b", 1]'); +----------------------------+ | JSON_TYPE('["a", "b", 1]') | +----------------------------+ | ARRAY | +----------------------------+ 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 处理在 JSON 上下文中使用的字符串时,使用utf8mb4
字符集和utf8mb4_bin
排序规则。其他字符集中的字符串会根据需要转换为utf8mb4
。(对于ascii
或utf8mb3
字符集中的字符串,不需要转换,因为ascii
和utf8mb3
是utf8mb4
的子集。)
作为使用文字字符串编写 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_PRESERVE()
接受两个或多个 JSON 文档并返回合并的结果:
mysql> SELECT JSON_MERGE_PRESERVE('["a", 1]', '{"key": "value"}');
+-----------------------------------------------------+
| JSON_MERGE_PRESERVE('["a", 1]', '{"key": "value"}') |
+-----------------------------------------------------+
| ["a", 1, {"key": "value"}] |
+-----------------------------------------------------+
1 row in set (0.00 sec)
关于合并规则的信息,请参见 JSON 值的规范化、合并和自动包装。
(MySQL 8.0.3 及更高版本还支持JSON_MERGE_PATCH()
,其行为略有不同。有关这两个函数之间差异的信息,请参见 JSON_MERGE_PATCH()与 JSON_MERGE_PRESERVE()的比较 compared with JSON_MERGE_PRESERVE()")。)
JSON 值可以分配给用户定义的变量:
mysql> SET @j = JSON_OBJECT('key', 'value');
mysql> SELECT @j;
+------------------+
| @j |
+------------------+
| {"key": "value"} |
+------------------+
然而,用户定义的变量不能是JSON
数据类型,因此,尽管前面示例中的@j
看起来像一个 JSON 值,并且具有与 JSON 值相同的字符集和校对规则,但它不具有JSON
数据类型。相反,当分配给变量时,JSON_OBJECT()
的结果会被转换为字符串。
通过转换 JSON 值生成的字符串具有utf8mb4
字符集和utf8mb4_bin
校对规则:
mysql> SELECT CHARSET(@j), COLLATION(@j);
+-------------+---------------+
| CHARSET(@j) | COLLATION(@j) |
+-------------+---------------+
| utf8mb4 | utf8mb4_bin |
+-------------+---------------+
因为utf8mb4_bin
是一个二进制校对规则,所以 JSON 值的比较是区分大小写的。
mysql> SELECT JSON_ARRAY('x') = JSON_ARRAY('X');
+-----------------------------------+
| JSON_ARRAY('x') = JSON_ARRAY('X') |
+-----------------------------------+
| 0 |
+-----------------------------------+
区分大小写也适用于 JSON 的null
、true
和false
字面量,它们必须始终以小写形式编写:
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 的NULL
、TRUE
和FALSE
字面量的大小写敏感性不同,后者可以以任何大小写形式编写:
mysql> SELECT ISNULL(null), ISNULL(Null), ISNULL(NULL);
+--------------+--------------+--------------+
| ISNULL(null) | ISNULL(Null) | ISNULL(NULL) |
+--------------+--------------+--------------+
| 1 | 1 | 1 |
+--------------+--------------+--------------+
有时可能需要或希望将引号字符("
或'
)插入 JSON 文档中。假设为此示例,您想要插入一些包含表示关于 MySQL 的一些事实的句子的 JSON 对象,每个句子都与适当的关键字配对,插入到使用下面显示的 SQL 语句创建的表中:
mysql> CREATE TABLE facts (sentence JSON);
在这些关键字-句子对中,有这样一个:
mascot: The MySQL mascot is a dolphin named "Sakila".
将此作为 JSON 对象插入facts
表中的一种方法是使用 MySQL 的JSON_OBJECT()
函数。在这种情况下,必须使用反斜杠转义每个引号字符,如下所示:
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
作为关键字的特定句子,可以使用列路径运算符->
,如下所示:
mysql> SELECT col->"$.mascot" FROM qtest;
+---------------------------------------------+
| col->"$.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". |
+-----------------------------------------+
注意
如果启用了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()
函数的描述。
JSON 值的规范化、合并和自动包装
当解析字符串并发现其为有效的 JSON 文档时,也会进行规范化。这意味着具有与后面在文档中找到的重复键的成员,从左到右阅读,将被丢弃。以下JSON_OBJECT()
调用生成的对象值仅包含第二个key1
元素,因为该键名在值中较早出现,如下所示:
mysql> SELECT JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def');
+------------------------------------------------------+
| JSON_OBJECT('key1', 1, 'key2', 'abc', 'key1', 'def') |
+------------------------------------------------------+
| {"key1": "def", "key2": "abc"} |
+------------------------------------------------------+
当值插入 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": "red"} |
| {"x": [3, 5, 7]} |
+------------------+
这种“最后一个重复键胜出”的行为是由RFC 7159建议的,并且大多数 JavaScript 解析器都实现了这种行为。(Bug #86866,Bug #26369555)
在 MySQL 8.0.3 之前的版本中,具有与文档中较早找到的键重复的成员将被丢弃。以下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"} |
+------------------------------------------------------+
在 MySQL 8.0.3 之前,插入 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 还会丢弃原始 JSON 文档中键、值或元素之间的额外空格,并在显示时在每个逗号(,
)或冒号(:
)后留下(或在必要时插入)一个空格。这样做是为了增强可读性。
生成 JSON 值的 MySQL 函数(请参阅第 14.17.2 节,“创建 JSON 值的函数”)始终返回规范化值。
为了使查找更有效率,MySQL 还对 JSON 对象的键进行排序。您应该注意,此排序的结果可能会发生变化,并且不能保证在不同版本之间保持一致。
合并 JSON 值
MySQL 8.0.3(以及更高版本)支持两种合并算法,由函数JSON_MERGE_PRESERVE()
和JSON_MERGE_PATCH()
实现。它们在处理重复键时有所不同:JSON_MERGE_PRESERVE()
保留重复键的值,而JSON_MERGE_PATCH()
丢弃除最后一个值之外的所有值。接下来的几段将解释这两个函数如何处理不同组合的 JSON 文档(即对象和数组)的合并。
注意
JSON_MERGE_PRESERVE()
与 MySQL 先前版本中的JSON_MERGE()
函数相同(在 MySQL 8.0.3 中更名)。JSON_MERGE()
在 MySQL 8.0 中仍作为JSON_MERGE_PRESERVE()
的别名受支持,但已被弃用,并可能在将来的版本中被移除。
合并数组。 在合并多个数组的上下文中,这些数组会合并为一个单一的数组。JSON_MERGE_PRESERVE()
通过将后面命名的数组连接到第一个数组的末尾来实现这一点。JSON_MERGE_PATCH()
将每个参数视为由单个元素组成的数组(因此其索引为 0),然后应用“最后重复键获胜”的逻辑,仅选择最后一个参数。您可以通过此查询比较所示的结果:
mysql> SELECT
-> JSON_MERGE_PRESERVE('[1, 2]', '["a", "b", "c"]', '[true, false]') AS Preserve,
-> JSON_MERGE_PATCH('[1, 2]', '["a", "b", "c"]', '[true, false]') AS Patch\G
*************************** 1\. row ***************************
Preserve: [1, 2, "a", "b", "c", true, false]
Patch: [true, false]
多个对象合并后产生一个单一对象。JSON_MERGE_PRESERVE()
通过将具有相同键的多个对象的所有唯一值组合为一个数组来处理这些对象;然后该数组被用作结果中该键的值。JSON_MERGE_PATCH()
丢弃发现重复键的值,从左到右工作,因此结果仅包含该键的最后一个值。以下查询说明了对重复键a
的结果差异:
mysql> SELECT
-> JSON_MERGE_PRESERVE('{"a": 1, "b": 2}', '{"c": 3, "a": 4}', '{"c": 5, "d": 3}') AS Preserve,
-> JSON_MERGE_PATCH('{"a": 3, "b": 2}', '{"c": 3, "a": 4}', '{"c": 5, "d": 3}') AS Patch\G
*************************** 1\. row ***************************
Preserve: {"a": [1, 4], "b": 2, "c": [3, 5], "d": 3}
Patch: {"a": 4, "b": 2, "c": 5, "d": 3}
在需要数组值的上下文中使用非数组值时,会自动包装:该值会被[
和]
字符包围以转换为数组。在下面的语句中,每个参数都被自动包装为一个数组([1]
,[2]
)。然后这些数组被合并为一个单一的结果数组;与前两种情况一样,JSON_MERGE_PRESERVE()
会合并具有相同键的值,而JSON_MERGE_PATCH()
会丢弃所有重复键的值,除了最后一个,如下所示:
mysql> SELECT
-> JSON_MERGE_PRESERVE('1', '2') AS Preserve,
-> JSON_MERGE_PATCH('1', '2') AS Patch\G
*************************** 1\. row ***************************
Preserve: [1, 2]
Patch: 2
数组和对象值通过将对象自动包装为数组并根据合并函数的选择(JSON_MERGE_PRESERVE()
或JSON_MERGE_PATCH()
)合并数组中的值或“最后重复键获胜”来进行合并,如本例所示:
mysql> SELECT
-> JSON_MERGE_PRESERVE('[10, 20]', '{"a": "x", "b": "y"}') AS Preserve,
-> JSON_MERGE_PATCH('[10, 20]', '{"a": "x", "b": "y"}') AS Patch\G
*************************** 1\. row ***************************
Preserve: [10, 20, {"a": "x", "b": "y"}]
Patch: {"a": "x", "b": "y"}
搜索和修改 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
上,命名数组中位置为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)
-
[*
M* to *
N*]
指定从位置M
开始,到位置N
结束的数组值的子集或范围。last
被支持作为最右边数组元素的索引的同义词。也支持数组元素的相对寻址。如果path
没有选择一个数组值,path
[last]会评估为与path
相同的值,如本节后面所示(参见最右边数组元素)。 -
路径可以包含
*
或**
通配符:-
.[*]
评估为 JSON 对象中所有成员的值。 -
[*]
评估为 JSON 数组中所有元素的值。 -
*
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[*]');
+------------------------------------------------------------+
| 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] |
+---------------------------------------------------------+
来自 JSON 数组的范围。 您可以使用to
关键字与范围一起指定 JSON 数组的子集。例如,$[1 to 3]
包括数组的第二、第三和第四个元素,如下所示:
mysql> SELECT JSON_EXTRACT('[1, 2, 3, 4, 5]', '$[1 to 3]');
+----------------------------------------------+
| JSON_EXTRACT('[1, 2, 3, 4, 5]', '$[1 to 3]') |
+----------------------------------------------+
| [2, 3, 4] |
+----------------------------------------------+
1 row in set (0.00 sec)
语法是*
M* to *
N*
,其中M
和N
分别是 JSON 数组中一系列元素的第一个和最后一个索引。N
必须大于M
;M
必须大于或等于 0。数组元素从 0 开始索引。
您可以在支持通配符的上下文中使用范围。
最右侧的数组元素。 last
关键字可用作数组中最后一个元素的索引的同义词。形式为last - *
N*
的表达式可用于相对寻址,以及在范围定义中,如下所示:
mysql> SELECT JSON_EXTRACT('[1, 2, 3, 4, 5]', '$[last-3 to last-1]');
+--------------------------------------------------------+
| JSON_EXTRACT('[1, 2, 3, 4, 5]', '$[last-3 to last-1]') |
+--------------------------------------------------------+
| [2, 3, 4] |
+--------------------------------------------------------+
1 row in set (0.01 sec)
如果路径针对的值不是数组,则评估的结果与将该值包装在单元素数组中的结果相同:
mysql> SELECT JSON_REPLACE('"Sakila"', '$[last]', 10);
+-----------------------------------------+
| JSON_REPLACE('"Sakila"', '$[last]', 10) |
+-----------------------------------------+
| 10 |
+-----------------------------------------+
1 row in set (0.00 sec)
您可以使用*
column*->*
path*
作为 JSON 列标识符和 JSON 路径表达式的同义词,用于JSON_EXTRACT(*
column*, *
path*)
。有关更多信息,请参见第 14.17.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]] |
+-----------------------------------------------+
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]
匹配不到任何内容:该元素已被移除,路径不再存在,也不产生任何效果。
JSON 路径语法
MySQL 支持的许多 JSON 函数在本手册的其他地方有描述(请参见第 14.17 节,“JSON 函数”,在ECMAScript 语言规范中)。路径表达式和 JSON 文本应使用ascii
,utf8mb3
或utf8mb4
字符集进行编码。其他字符编码将被隐式强制转换为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 8.0 不支持这些功能。
通配符*
和**
标记的使用如下:
-
.*
代表对象中所有成员的值。 -
[*]
代表数组中所有单元格的值。 -
[*
前缀*]***
后缀*
代表以前缀
开头并以后缀
结尾的所有路径。前缀
是可选的,而后缀
是必需的;换句话说,路径不能以**
结尾。另外,路径中不能包含序列
***
。
有关路径语法示例,请参阅各种接受路径作为参数的 JSON 函数的描述,例如JSON_CONTAINS_PATH()
,JSON_SET()
和JSON_REPLACE()
。有关包含*
和**
通配符的示例,请参阅JSON_SEARCH()
函数的描述。
MySQL 8.0 还支持使用to
关键字对 JSON 数组的子集进行范围表示(例如$[2 to 10]
),以及使用last
关键字作为数组最右侧元素的同义词。有关更多信息和示例,请参见搜索和修改 JSON 值。
JSON 值的比较和排序
可以使用=
、<
、<=
、>
、>=
、<>
、!=
和<=>
运算符来比较 JSON 值。
尚不支持以下比较运算符和函数与 JSON 值一起使用:
-
BETWEEN
-
IN()
-
GREATEST()
-
LEAST()
对于刚刚列出的比较运算符和函数的解决方法是将 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 的
DATETIME
和TIMESTAMP
类型,则如果它们表示相同的时间点,则它们相等。 -
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
排序规则的 SQL 字符串的排序。因为utf8mb4_bin
有一个二进制排序规则,所以 JSON 值的比较是区分大小写的:"A" < "a"
-
INTEGER
,DOUBLE
JSON 值可以包含精确值和近似值数字。有关这些类型数字的一般讨论,请参见第 11.1.2 节,“数字文字”。
讨论了比较本机 MySQL 数值类型的规则在第 14.3 节,“表达式求值中的类型转换”中,但是比较 JSON 值中的数字的规则略有不同:
-
在比较使用本机 MySQL
INT
- INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT") 和DOUBLE
- FLOAT, DOUBLE") 数值类型的两列时,已知所有比较涉及整数和双精度数,因此整数被转换为双精度以用于所有行。也就是说,精确值数字被转换为近似值数字。 -
另一方面,如果查询比较包含数字的两个 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 值与 SQL NULL
的比较结果为UNKNOWN
。
对于 JSON 和非 JSON 值的比较,根据以下表中的规则将非 JSON 值转换为 JSON,然后按照先前描述的方式进行比较。
在 JSON 值和非 JSON 值之间转换
以下表格总结了 MySQL 在 JSON 值和其他类型值之间转换时遵循的规则:
表 13.3 JSON 转换规则
其他类型 | CAST(other type AS JSON) | CAST(JSON AS other type) |
---|---|---|
JSON | 无变化 | 无变化 |
utf8 字符类型(utf8mb4 ,utf8mb3 ,ascii ) |
字符串被解析为 JSON 值。 | JSON 值被序列化为utf8mb4 字符串。 |
其他字符类型 | 其他字符编码会隐式转换为utf8mb4 ,并按照该字符类型描述的方式处理。 |
JSON 值被序列化为utf8mb4 字符串,然后转换为其他字符编码。结果可能无意义。 |
NULL |
结果为 JSON 类型的NULL 值。 |
不适用。 |
几何类型 | 几何值通过调用 ST_AsGeoJSON() 转换为 JSON 文档。 |
非法操作。解决方法:将 CAST(* json_val* AS CHAR) 的结果传递给 ST_GeomFromGeoJSON() 。 |
所有其他类型 | 结果为由单个标量值组成的 JSON 文档。 | 如果 JSON 文档由目标类型的单个标量值组成且该标量值可以转换为目标类型,则成功。否则,返回NULL 并产生警告。 |
对于 JSON 值,ORDER BY
和 GROUP BY
遵循以下原则:
-
标量 JSON 值的排序使用与前述讨论相同的规则。
-
对于升序排序,SQL
NULL
排在所有 JSON 值之前,包括 JSON 的 null 字面量;对于降序排序,SQLNULL
排在所有 JSON 值之后,包括 JSON 的 null 字面量。 -
JSON 值的排序键受
max_sort_length
系统变量的值限制,因此仅在首个max_sort_length
字节之后有差异的键将被视为相等。 -
非标量值的排序目前不受支持,会出现警告。
对于排序,将 JSON 标量转换为其他本机 MySQL 类型可能是有益的。例如,如果名为jdoc
的列包含具有由id
键和非负值组成的成员的 JSON 对象,则使用此表达式按id
值排序:
ORDER BY CAST(JSON_EXTRACT(jdoc, '$.id') AS UNSIGNED)
如果存在一个生成的列被定义为使用与ORDER BY
相同的表达式,MySQL 优化器会识别并考虑在查询执行计划中使用该索引。参见 Section 10.3.11, “生成列索引的优化器使用”。
JSON 值的聚合
对于 JSON 值的聚合,SQL NULL
值会被忽略,就像其他数据类型一样。非NULL
值会被转换为数值类型并进行聚合,除了 MIN()
, MAX()
, 和 GROUP_CONCAT()
。对于 JSON 值转换为数字应该会产生有意义的结果,尽管(取决于值)可能会发生截断和精度丢失。其他 JSON 值的转换为数字可能不会产生有意义的结果。
13.6 数据类型默认值
数据类型规范可以具有显式或隐式默认值。
数据类型规范中的DEFAULT *
value*
子句明确指示了列的默认值。例如:
CREATE TABLE t1 (
i INT DEFAULT -1,
c VARCHAR(10) DEFAULT '',
price DOUBLE(16,2) DEFAULT 0.00
);
SERIAL DEFAULT VALUE
是一个特殊情况。在整数列的定义中,它是NOT NULL AUTO_INCREMENT UNIQUE
的别名。
显式DEFAULT
子句处理的某些方面取决于版本,如下所述。
MySQL 8.0.13 之后的显式默认处理
在DEFAULT
子句中指定的默认值可以是字面常量或表达式。除了一个例外,将表达式默认值括在括号中以区分它们与字面常量默认值。例如:
CREATE TABLE t1 (
-- literal defaults
i INT DEFAULT 0,
c VARCHAR(10) DEFAULT '',
-- expression defaults
f FLOAT DEFAULT (RAND() * RAND()),
b BINARY(16) DEFAULT (UUID_TO_BIN(UUID())),
d DATE DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR),
p POINT DEFAULT (Point(0,0)),
j JSON DEFAULT (JSON_ARRAY())
);
例外情况是,对于TIMESTAMP
和DATETIME
列,您可以指定CURRENT_TIMESTAMP
函数作为默认值,而无需括号。请参阅第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”。
只有将BLOB
、TEXT
、GEOMETRY
和JSON
数据类型写为表达式时,才能为其分配默认值,即使表达式值是字面值:
-
这是允许的(将字面默认指定为表达式):
CREATE TABLE t2 (b BLOB DEFAULT ('abc'));
-
这会产生一个错误(未将字面默认指定为表达式):
CREATE TABLE t2 (b BLOB DEFAULT 'abc');
表达式默认值必须遵守以下规则。如果表达式包含不允许的结构,则会发生错误。
-
字面常量、内置函数(确定性和非确定性)和运算符是允许的。
-
子查询、参数、变量、存储函数和可加载函数不被允许。
-
表达式默认值不能依赖于具有
AUTO_INCREMENT
属性的列。 -
一个列的表达式默认值可以引用其他表列,但是不能引用生成列或具有表达式默认值的列,除非这些列在表定义中出现在前面。也就是说,表达式默认值不能包含对生成列或具有表达式默认值的列的前向引用。
排序约束也适用于使用
ALTER TABLE
重新排序表列。如果结果表会有一个包含对生成列或具有表达式默认值的列的前向引用的表达式默认值,则该语句将失败。
注意
如果表达式默认值的任何组件依赖于 SQL 模式,除非在所有使用期间 SQL 模式相同,否则对表的不同使用可能会导致不同的结果。
对于CREATE TABLE ... LIKE
和CREATE TABLE ... SELECT
,目标表会保留原始表的表达式默认值。
如果表达式默认值引用了一个非确定性函数,任何导致表达式被评估的语句对于基于语句的复制都是不安全的。这包括诸如INSERT
和UPDATE
之类的语句。在这种情况下,如果二进制日志记录被禁用,该语句将正常执行。如果启用了二进制日志记录并且binlog_format
设置为STATEMENT
,则该语句将被记录并执行,但会向错误日志写入警告消息,因为复制从机可能会发散。当binlog_format
设置为MIXED
或ROW
时,该语句将正常执行。
在插入新行时,具有表达式默认值的列的默认值可以通过省略列名或将列指定为DEFAULT
来插入(与具有文字默认值的列一样):
mysql> CREATE TABLE t4 (uid BINARY(16) DEFAULT (UUID_TO_BIN(UUID())));
mysql> INSERT INTO t4 () VALUES();
mysql> INSERT INTO t4 () VALUES(DEFAULT);
mysql> SELECT BIN_TO_UUID(uid) AS uid FROM t4;
+--------------------------------------+
| uid |
+--------------------------------------+
| f1109174-94c9-11e8-971d-3bf1095aa633 |
| f110cf9a-94c9-11e8-971d-3bf1095aa633 |
+--------------------------------------+
然而,使用DEFAULT(*
col_name*)
为命名列指定默认值仅适用于具有文字默认值的列,而不适用于具有表达式默认值的列。
不是所有存储引擎都允许表达式默认值。对于那些不允许的引擎,会出现ER_UNSUPPORTED_ACTION_ON_DEFAULT_VAL_GENERATED
错误。
如果默认值计算结果的数据类型与声明的列类型不同,根据通常的 MySQL 类型转换规则会发生隐式强制转换到声明的类型。参见 第 14.3 节,“表达式评估中的类型转换”。
显式默认处理在 MySQL 8.0.13 之前
除了一个例外,DEFAULT
子句中指定的默认值必须是字面常量;它不能是函数或表达式。这意味着,例如,你不能将日期列的默认值设置为函数值,如NOW()
或CURRENT_DATE
。例外是,对于TIMESTAMP
和DATETIME
列,你可以指定CURRENT_TIMESTAMP
作为默认值。参见 第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”。
BLOB
、TEXT
、GEOMETRY
和 JSON
数据类型不能被分配默认值。
如果默认值计算结果的数据类型与声明的列类型不同,根据通常的 MySQL 类型转换规则会发生隐式强制转换到声明的类型。参见 第 14.3 节,“表达式评估中的类型转换”。
隐式默认处理
如果数据类型规范中不包含显式DEFAULT
值,MySQL 将确定默认值如下:
如果列可以接受NULL
作为值,则该列将定义为带有显式DEFAULT NULL
子句的列。
如果列不能接受NULL
作为值,MySQL 将定义不带显式DEFAULT
子句的列。
对于没有显式DEFAULT
子句的NOT NULL
列的数据输入,如果INSERT
或REPLACE
语句不包含该列的值,或者UPDATE
语句将列设置为NULL
,MySQL 根据当时有效的 SQL 模式处理该列:
-
如果启用了严格的 SQL 模式,对于事务表会发生错误并回滚该语句。对于非事务表,会发生错误,但如果这发生在多行语句的第二行或后续行,前面的行将被插入。
-
如果未启用严格模式,MySQL 会将列设置为列数据类型的隐式默认值。
假设表t
定义如下:
CREATE TABLE t (i INT NOT NULL);
在这种情况下,i
没有显式默认值,因此在严格模式下,以下每个语句都会产生错误,且不会插入行。当不使用严格模式时,只有第三个语句会产生错误;前两个语句会插入隐式默认值,但第三个会失败,因为DEFAULT(i)
无法产生值:
INSERT INTO t VALUES();
INSERT INTO t VALUES(DEFAULT);
INSERT INTO t VALUES(DEFAULT(i));
参见第 7.1.11 节,“服务器 SQL 模式”。
对于给定表,SHOW CREATE TABLE
语句显示哪些列具有显式的DEFAULT
子句。
隐式默认值定义如下:
-
对于数值类型,默认值为
0
,但对于声明了AUTO_INCREMENT
属性的整数或浮点数类型,其默认值为序列中的下一个值。 -
对于除
TIMESTAMP
之外的日期和时间类型,其默认值为该类型的适当“零”值。如果启用了explicit_defaults_for_timestamp
系统变量(参见第 7.1.8 节,“服务器系统变量”),则对于TIMESTAMP
也是如此。否则,对于表中的第一个TIMESTAMP
列,其默认值为当前日期和时间。参见第 13.2 节,“日期和时间数据类型”。 -
对于除
ENUM
之外的字符串类型,默认值为空字符串。对于ENUM
,默认值为第一个枚举值。
13.7 数据类型存储要求
原文:
dev.mysql.com/doc/refman/8.0/en/storage-requirements.html
-
InnoDB 表存储要求
-
NDB 表存储要求
-
数值类型存储要求
-
日期和时间类型存储要求
-
字符串类型存储要求
-
空间类型存储要求
-
JSON 存储要求
磁盘上表数据的存储要求取决于几个因素。不同的存储引擎表示数据类型并以不同方式存储原始数据。表数据可能会被压缩,无论是针对列还是整个行,这会使得计算表或列的存储要求变得复杂。
尽管在磁盘上存储布局存在差异,但内部 MySQL API 用于通信和交换关于表行的信息的数据结构是一致的,适用于所有存储引擎。
本节包括 MySQL 支持的每种数据类型的存储要求的指南和信息,包括对使用固定大小表示数据类型的存储引擎的内部格式和大小的描述。信息按类别或存储引擎列出。
表的内部表示最大行大小为 65,535 字节,即使存储引擎能够支持更大的行也是如此。这个数字不包括BLOB
或TEXT
列,这些列只对这个大小贡献了 9 到 12 个字节。对于BLOB
和TEXT
数据,信息存储在内存的不同区域中,而不是行缓冲区。不同的存储引擎根据它们用于处理相应类型的方法以不同的方式处理这些数据的分配和存储。有关更多信息,请参见第十八章,替代存储引擎和第 10.4.7 节,“表列计数和行大小限制”。
InnoDB 表存储要求
有关InnoDB
表的存储要求,请参见第 17.10 节“InnoDB 行格式”。
NDB 表存储要求
重要提示
NDB
表使用 4 字节对齐;所有NDB
数据存储都是 4 字节的倍数。因此,在NDB
表中,通常需要 15 字节的列值需要 16 字节。例如,在NDB
表中,TINYINT
、SMALLINT
、MEDIUMINT
和INTEGER
(INT
)列类型每个记录需要 4 字节的存储空间,这是由于对齐因素。
每个BIT(*M*)
列占用M位的存储空间。虽然单个BIT
列不是 4 字节对齐,但是NDB
每行为BIT
列的前 1-32 位保留 4 字节(32 位),然后为第 33-64 位保留另外 4 字节,依此类推。
虽然NULL
本身不需要任何存储空间,但是如果表定义包含允许NULL
的列,NDB
每行将保留 4 个字节,最多 32 个NULL
列。(如果 NDB Cluster 表定义中包含超过 32 个NULL
列,最多 64 个NULL
列,则每行将保留 8 个字节。)
每个使用NDB
存储引擎的表都需要一个主键;如果您没有定义主键,NDB
将创建一个“隐藏”主键。这个隐藏主键每个表记录消耗 31-35 字节。
您可以使用 ndb_size.pl Perl 脚本来估算NDB
的存储需求。它连接到当前的 MySQL(而不是 NDB Cluster)数据库,并创建一个关于如果该数据库使用NDB
存储引擎将需要多少空间的报告。有关更多信息,请参见 第 25.5.28 节“ndb_size.pl — NDBCLUSTER Size Requirement Estimator”。
数值类型存储需求
数据类型 | 所需存储空间 |
---|---|
TINYINT |
1 字节 |
SMALLINT |
2 字节 |
MEDIUMINT |
3 字节 |
INT , INTEGER |
4 字节 |
BIGINT |
8 字节 |
FLOAT(* p*) |
如果 0 <= p <= 24,则为 4 字节,如果 25 <= p <= 53,则为 8 字节 |
FLOAT |
4 字节 |
DOUBLE [PRECISION] , REAL |
8 字节 |
DECIMAL(* M*,* D*) , NUMERIC(* M*,* D*) |
变化;参见下面的讨论 |
BIT(* M*) |
大约(M +7)/8 字节 |
数据类型 | 所需存储空间 |
DECIMAL
(以及NUMERIC
列使用一种二进制格式表示,将九个十进制(十进制)数字打包成四个字节。每个值的整数部分和小数部分的存储是分开确定的。每个九位数字的倍数需要四个字节,“剩余”数字需要四个字节的一部分。多余数字所需的存储空间由下表给出。
剩余数字 | 字节数 |
---|---|
0 | 0 |
1 | 1 |
2 | 1 |
3 | 2 |
4 | 2 |
5 | 3 |
6 | 3 |
7 | 4 |
8 | 4 |
日期和时间类型存储需求
对于 TIME
、DATETIME
和 TIMESTAMP
列,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 版本,YEAR
和 DATE
的存储方式保持不变。然而,TIME
、DATETIME
和 TIMESTAMP
的表示方式有所不同。DATETIME
被更有效地打包,非分数部分只需 5 个字节,而不是 8 个字节,而且所有三部分都有一个分数部分,根据存储值的分数秒精度,需要从 0 到 3 个字节。
分数秒精度 | 所需存储空间 |
---|---|
0 | 0 字节 |
1, 2 | 1 字节 |
3, 4 | 2 字节 |
5, 6 | 3 字节 |
例如,TIME(0)
、TIME(2)
、TIME(4)
和 TIME(6)
分别使用 3、4、5 和 6 个字节。TIME
和 TIME(0)
是等效的,需要相同的存储空间。
有关时间值的内部表示的详细信息,请参阅 MySQL Internals: Important Algorithms and Structures。
字符串类型存储要求
在下表中,M
代表非二进制字符串类型的声明列长度(以字符计)和二进制字符串类型的字节数。L
代表给定字符串值的实际字节长度。
数据类型 | 所需存储空间 |
---|---|
CHAR(* M*) |
InnoDB 行格式的紧凑系列优化了变长字符集的存储。请参阅 COMPACT 行格式存储特性。否则,M × w 字节,<= * M* <= 255,其中w 是字符集中最大长度字符所需的字节数。 |
BINARY(* M*) |
M 字节,0 <= * M* <= 255 |
VARCHAR(* M*) , VARBINARY(* M*) |
如果列值需要 0 − 255 字节,则为L + 1 字节,如果值可能需要超过 255 字节,则为L + 2 字节 |
TINYBLOB , TINYTEXT |
L + 1 字节,其中L < 2⁸ |
BLOB , TEXT |
L + 2 字节,其中L < 2¹⁶ |
MEDIUMBLOB , MEDIUMTEXT |
L + 3 字节,其中L < 2²⁴ |
LONGBLOB , LONGTEXT |
L + 4 字节,其中L < 2³² |
ENUM('* value1*','* value2*',...) |
1 或 2 字节,取决于枚举值的数量(最多 65,535 个值) |
SET('* value1*','* value2*',...) |
1、2、3、4 或 8 字节,取决于集合成员的数量(最多 64 个成员) |
变长字符串类型使用长度前缀加数据进行存储。长度前缀根据数据类型需要占用一到四个字节不等,前缀的值为L
(字符串的字节长度)。例如,存储MEDIUMTEXT
值需要L
字节来存储值,再加上三个字节来存储值的长度。
要计算存储特定CHAR
、VARCHAR
或TEXT
列值所需的字节数,必须考虑用于该列的字符集以及值是否包含多字节字符。特别是在使用 UTF-8 Unicode 字符集时,必须记住并非所有字符使用相同数量的字节。utf8mb3
和utf8mb4
字符集分别可以每个字符需要最多三个和四个字节。有关不同类别utf8mb3
或utf8mb4
字符所使用的存储的详细信息,请参见第 12.9 节“Unicode 支持”。
VARCHAR
、VARBINARY
、BLOB
和 TEXT
类型是可变长度类型。对于每种类型,存储需求取决于以下因素:
-
列值的实际长度
-
列的最大可能长度
-
列使用的字符集,因为某些字符集包含多字节字符
例如,VARCHAR(255)
列可以容纳最大长度为 255 个字符的字符串。假设该列使用 latin1
字符集(每个字符一个字节),实际所需存储空间是字符串的长度(L
),再加上一个字节来记录字符串的长度。对于字符串 'abcd'
,L
为 4,存储需求为五个字节。如果相同列改为使用 ucs2
双字节字符集,则存储需求为 10 个字节:'abcd'
的长度为八个字节,列需要两个字节来存储长度,因为最大长度大于 255(最多 510 个字节)。
可存储在 VARCHAR
或 VARBINARY
列中的有效最大 字节数 受限于 65,535 字节的最大行大小,该大小在所有列之间共享。对于存储多字节字符的 VARCHAR
列,有效最大 字符数 较少。例如,utf8mb4
字符可能每个字符需要最多四个字节,因此使用 utf8mb4
字符集的 VARCHAR
列最多可以声明为 16,383 个字符。参见 第 10.4.7 节,“表列数和行大小的限制”。
InnoDB
将长度大于或等于 768 个字节的固定长度字段编码为可变长度字段,可以存储在页外。例如,如果 CHAR(255)
列的字符集的最大字节长度大于 3,比如 utf8mb4
,则可以超过 768 个字节。
NDB
存储引擎支持可变宽度列。这意味着在 NDB Cluster 表中,VARCHAR
列需要与任何其他存储引擎相同的存储空间,唯一的例外是这些值是 4 字节对齐的。因此,在使用 latin1
字符集的 VARCHAR(50)
列中存储的字符串 'abcd'
需要 8 字节(而不是在 MyISAM
表中相同列值的 5 字节)。
TEXT
, BLOB
和 JSON
列在 NDB
存储引擎中实现方式不同,其中列中的每一行由两个独立部分组成。其中一个是固定大小的(TEXT
和 BLOB
为 256 字节,JSON
为 4000 字节),实际上存储在原始表中。另一个部分包含超过 256 字节的任何数据,存储在隐藏的 blob 部分表中。第二个表中行的大小由列的确切类型确定,如下表所示:
类型 | Blob 部分大小 |
---|---|
BLOB , TEXT |
2000 |
MEDIUMBLOB , MEDIUMTEXT |
4000 |
LONGBLOB , LONGTEXT |
13948 |
JSON |
8100 |
这意味着如果 size
<= 256(其中 size
表示行的大小),则 TEXT
列的大小为 256;否则,大小为 256 + size
+ (2000 × (size
− 256) % 2000)。
NDB
不会为 TINYBLOB
或 TINYTEXT
列值单独存储 blob 部分。
可以使用 NDB_COLUMN
在创建或更改父表时在列注释中将 NDB
blob 列的 blob 部分大小增加到最大值 13948。在 NDB 8.0.30 及更高版本中,还可以使用 NDB_TABLE
在列注释中设置 TEXT
、BLOB
或 JSON
列的内联大小。有关更多信息,请参见 NDB_COLUMN 选项。
ENUM
对象的大小由不同枚举值的数量确定。对于最多有 255 个可能值的枚举,使用一个字节。对于具有 256 到 65,535 个可能值的枚举,使用两个字节。请参见 第 13.3.5 节,“ENUM 类型”。
SET
对象的大小由不同集合成员的数量确定。如果集合大小为 N
,则对象占用 (*
N*+7)/8
字节,向上取整为 1、2、3、4 或 8 字节。SET
最多可以有 64 个成员。请参见 第 13.3.6 节,“SET 类型”。
空间类型存储要求
MySQL 使用 4 个字节来存储几何值的 SRID,后跟值的 WKB 表示。LENGTH()
函数返回存储值所需的字节空间。
有关空间值的 WKB 和内部存储格式的描述,请参阅第 13.4.3 节,“支持的空间数据格式”。
JSON 存储需求
一般来说,JSON
列的存储需求大致与 LONGBLOB
或 LONGTEXT
列相同;也就是说,JSON 文档所占用的空间大致与存储在这些类型列中的文档的字符串表示相同。然而,由于存储在 JSON 文档中的各个值的二进制编码,包括用于查找的元数据和字典,会带来一些额外开销。例如,存储在 JSON 文档中的字符串需要额外的 4 到 10 字节的存储空间,取决于字符串的长度以及存储它的对象或数组的大小。
此外,MySQL 对存储在 JSON
列中的任何 JSON 文档的大小施加了限制,使其不能大于 max_allowed_packet
的值。
13.8 选择适合列的正确类型
为了最佳存储,您应该尽量在所有情况下使用最精确的类型。例如,如果整数列用于范围在1
到99999
之间的值,MEDIUMINT UNSIGNED
是最佳类型。在表示所有所需值的类型中,此类型使用的存储空间最少。
所有基本计算(+
, -
, *
, 和 /
)与DECIMAL
列都以 65 位十进制(基数 10)数字的精度进行。参见 Section 13.1.1, “Numeric Data Type Syntax”。
如果精度不是太重要,或者速度是最高优先级,DOUBLE
类型可能已经足够好了。对于高精度,您可以随时转换为存储在BIGINT
中的固定点类型。这使您可以使用 64 位整数进行所有计算,然后根据需要将结果转换回浮点值。
13.9 使用其他数据库引擎的数据类型
原文:
dev.mysql.com/doc/refman/8.0/en/other-vendor-data-types.html
为了方便使用来自其他供应商的 SQL 实现编写的代码,MySQL 将数据类型映射如下表所示。这些映射使得更容易将其他数据库系统的表定义导入到 MySQL 中。
其他供应商类型 | MySQL 类型 |
---|---|
BOOL |
TINYINT |
BOOLEAN |
TINYINT |
CHARACTER VARYING(* M*) |
VARCHAR(* M*) |
FIXED |
DECIMAL |
FLOAT4 |
FLOAT |
FLOAT8 |
DOUBLE |
INT1 |
TINYINT |
INT2 |
SMALLINT |
INT3 |
MEDIUMINT |
INT4 |
INT |
INT8 |
BIGINT |
LONG VARBINARY |
MEDIUMBLOB |
LONG VARCHAR |
MEDIUMTEXT |
LONG |
MEDIUMTEXT |
MIDDLEINT |
MEDIUMINT |
NUMERIC |
DECIMAL |
其他供应商类型 | MySQL 类型 |
数据类型映射发生在表创建时,之后原始类型规范被丢弃。如果你创建了一个使用其他供应商类型的表,然后发出一个DESCRIBE *tbl_name*
语句,MySQL 会使用等效的 MySQL 类型报告表结构。例如:
mysql> CREATE TABLE t (a BOOL, b FLOAT8, c LONG VARCHAR, d NUMERIC);
Query OK, 0 rows affected (0.00 sec)
mysql> DESCRIBE t;
+-------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| a | tinyint(1) | YES | | NULL | |
| b | double | YES | | NULL | |
| c | mediumtext | YES | | NULL | |
| d | decimal(10,0) | YES | | NULL | |
+-------+---------------+------+-----+---------+-------+
4 rows in set (0.01 sec)
第十四章 函数和运算符
目录
14.1 内置函数和运算符参考
14.2 可加载函数参考
14.3 表达式求值中的类型转换
14.4 运算符
14.4.1 运算符优先级
14.4.2 比较函数和运算符
14.4.3 逻辑运算符
14.4.4 赋值运算符
14.5 流程控制函数
14.6 数值函数和运算符
14.6.1 算术运算符
14.6.2 数学函数
14.7 日期和时间函数
14.8 字符串函数和运算符
14.8.1 字符串比较函数和运算符
14.8.2 正则表达式
14.8.3 函数结果的字符集和排序规则
14.9 全文搜索函数
14.9.1 自然语言全文搜索
14.9.2 布尔全文搜索
14.9.3 具有查询扩展的全文搜索
14.9.4 全文搜索停用词
14.9.5 全文搜索限制
14.9.6 调整 MySQL 全文搜索
14.9.7 为全文索引添加用户定义排序规则
14.9.8 ngram 全文解析器
14.9.9 MeCab 全文解析器插件
14.10 强制转换函数和运算符
14.11 XML 函数
14.12 位运算函数和运算符
14.13 加密和压缩函数
14.14 锁定函数
14.15 信息函数
14.16 空间分析函数
14.16.1 空间函数参考
14.16.2 空间函数的参数处理
14.16.3 从 WKT 值创建几何值的函数
14.16.4 从 WKB 值创建几何值的函数
14.16.5 MySQL 特定的从几何值创建函数
14.16.6 几何格式转换函数
14.16.7 几何属性函数
14.16.8 空间运算符函数
14.16.9 几何对象之间空间关系测试函数
14.16.10 空间 Geohash 函数
14.16.11 空间 GeoJSON 函数
14.16.12 空间聚合函数
14.16.13 空间便利函数
14.17 JSON 函数
14.17.1 JSON 函数参考
14.17.2 创建 JSON 值的函数
14.17.3 搜索 JSON 值的函数
14.17.4 修改 JSON 值的函数
14.17.5 返回 JSON 值属性的函数
14.17.6 JSON 表函数
14.17.7 JSON 模式验证函数
14.17.8 JSON 实用函数
14.18 复制函数
14.18.1 组复制函数
14.18.2 与全局事务标识符(GTID)一起使用的函数
14.18.3 异步复制通道故障转移函数
14.18.4 基于位置的同步函数
14.19 聚合函数
14.19.1 聚合函数描述
14.19.2 GROUP BY 修饰符
14.19.3 MySQL 处理 GROUP BY
14.19.4 功能依赖检测
14.20 窗口函数
14.20.1 窗口函数描述
14.20.2 窗口函数概念和语法
14.20.3 窗口函数框架规范
14.20.4 命名窗口
14.20.5 窗口函数限制
14.21 性能模式函数
14.22 内部函数
14.23 杂项函数
14.24 精确数学
14.24.1 数值类型
14.24.2 DECIMAL 数据类型特性
14.24.3 表达式处理
14.24.4 四舍五入行为
14.24.5 精确数学示例
表达式可以在 SQL 语句的多个位置中使用,例如在SELECT
语句的ORDER BY
或HAVING
子句中,在SELECT
、DELETE
或UPDATE
语句的WHERE
子句中,或在SET
语句中。表达式可以使用来自多个来源的值编写,例如文字值、列值、NULL
、变量、内置函数和运算符、可加载函数以及存储函数(一种存储对象类型)。
本章描述了在 MySQL 中允许用于编写表达式的内置函数和运算符。有关可加载函数和存储函数的信息,请参见第 7.7 节,“MySQL 服务器可加载函数”和第 27.2 节,“使用存储例程”。有关服务器解释对不同类型函数引用的规则,请参见第 11.2.5 节,“函数名称解析和解析”。
包含NULL
的表达式始终产生NULL
值,除非特定函数或运算符的文档另有说明。
注意
默认情况下,函数名称和其后的括号之间不能有空格。这有助于 MySQL 解析器区分函数调用和恰好与函数同名的表或列的引用。但是,函数参数周围的空格是允许的。
通过使用--sql-mode=IGNORE_SPACE
选项告诉 MySQL 服务器接受函数名称后的空格。 (请参见第 7.1.11 节,“服务器 SQL 模式”。)个别客户端程序可以通过在mysql_real_connect()
中使用CLIENT_IGNORE_SPACE
选项来请求此行为。在任一情况下,所有函数名称都变为保留字。
为简洁起见,本章中的一些示例以缩写形式显示了来自mysql程序的输出。而不是以这种格式显示示例:
mysql> SELECT MOD(29,9);
+-----------+
| mod(29,9) |
+-----------+
| 2 |
+-----------+
1 rows in set (0.00 sec)
取而代之的是使用此格式:
mysql> SELECT MOD(29,9);
-> 2
14.1 内置函数和运算符参考
原文:
dev.mysql.com/doc/refman/8.0/en/built-in-function-reference.html
以下表格列出了每个内置(原生)函数和运算符,并提供了每个的简短描述。有关在运行时可加载的函数列表,请参见第 14.2 节,“可加载函数参考”。
表格 14.1 内置函数和运算符
名称 | 描述 | 引入 | 废弃 |
---|---|---|---|
& |
按位与 | ||
> |
大于运算符 | ||
>> |
右移 | ||
>= |
大于或等于运算符 | ||
< |
小于运算符 | ||
<> , != |
不等于运算符 | ||
<< |
左移 | ||
<= |
小于或等于运算符 | ||
<=> |
NULL 安全等于运算符 | ||
% , MOD |
取模运算符 | ||
* |
乘法运算符 | ||
+ |
加法运算符 | ||
- |
减法运算符 | ||
- |
改变参数的符号 | ||
-> |
在评估路径后从 JSON 列返回值;相当于 JSON_EXTRACT()。 | ||
->> |
在评估路径并取消引用结果后从 JSON 列返回值;相当于 JSON_UNQUOTE(JSON_EXTRACT())。 | ||
/ |
除法运算符 | ||
:= |
赋值 | ||
= |
赋值(作为 SET 语句的一部分,或作为 UPDATE 语句中 SET 子句的一部分) |
||
= |
等于运算符 | ||
^ |
按位异或 | ||
ABS() |
返回绝对值 | ||
ACOS() |
返回反余弦 | ||
ADDDATE() |
将时间值(间隔)添加到日期值中 | ||
ADDTIME() |
添加时间 | ||
AES_DECRYPT() |
使用 AES 解密 | ||
AES_ENCRYPT() |
使用 AES 加密 | ||
AND , && |
逻辑与 | ||
ANY_VALUE() |
抑制 ONLY_FULL_GROUP_BY 值拒绝 | ||
ASCII() |
返回最左字符的数字值 | ||
ASIN() |
返回反正弦 | ||
asynchronous_connection_failover_add_managed() |
将组成员源服务器配置信息添加到复制通道源列表 | 8.0.23 | |
asynchronous_connection_failover_add_source() |
将源服务器配置信息添加到复制通道源列表 | 8.0.22 | |
asynchronous_connection_failover_delete_managed() |
从复制通道源列表中删除受管组 | 8.0.23 | |
asynchronous_connection_failover_delete_source() |
从复制通道源列表中删除源服务器 | 8.0.22 | |
asynchronous_connection_failover_reset() |
删除与组复制异步故障转移相关的所有设置 | 8.0.27 | |
ATAN() |
返回反正切 | ||
ATAN2() , ATAN() |
返回两个参数的反正切 | ||
AVG() |
返回参数的平均值 | ||
BENCHMARK() |
反复执行表达式 | ||
BETWEEN ... AND ... |
值是否在一系列值范围内 | ||
BIN() |
返回包含数字的二进制表示的字符串 | ||
BIN_TO_UUID() |
将二进制 UUID 转换为字符串 | ||
BINARY |
将字符串转换为二进制字符串 | 8.0.27 | |
BIT_AND() |
返回按位与 | ||
BIT_COUNT() |
返回设置的位数 | ||
BIT_LENGTH() |
返回参数的位长度 | ||
BIT_OR() |
返回按位或 | ||
BIT_XOR() |
返回按位异或 | ||
CAN_ACCESS_COLUMN() |
仅供内部使用 | ||
CAN_ACCESS_DATABASE() |
仅供内部使用 | ||
CAN_ACCESS_TABLE() |
仅供内部使用 | ||
CAN_ACCESS_USER() |
仅供内部使用 | 8.0.22 | |
CAN_ACCESS_VIEW() |
仅供内部使用 | ||
CASE |
Case 运算符 | ||
CAST() |
将值转换为特定类型 | ||
CEIL() |
返回不小于参数的最小整数值 | ||
CEILING() |
返回不小于参数的最小整数值 | ||
CHAR() |
返回每个传递的整数的字符 | ||
CHAR_LENGTH() |
返回参数中的字符数 | ||
CHARACTER_LENGTH() |
CHAR_LENGTH()的同义词 | ||
CHARSET() |
返回参数的字符集 | ||
COALESCE() |
返回第一个非 NULL 参数 | ||
COERCIBILITY() |
返回字符串参数的排序强制性值 | ||
COLLATION() |
返回字符串参数的排序规则 | ||
COMPRESS() |
返回结果作为二进制字符串 | ||
CONCAT() |
返回连接的字符串 | ||
CONCAT_WS() |
返回带有分隔符的连接 | ||
CONNECTION_ID() |
返回连接的连接 ID(线程 ID) | ||
CONV() |
在不同进制之间转换数字 | ||
CONVERT() |
将值转换为特定类型 | ||
CONVERT_TZ() |
从一个时区转换到另一个时区 | ||
COS() |
返回余弦值 | ||
COT() |
返回余切 | ||
COUNT() |
返回返回的行数计数 | ||
COUNT(DISTINCT) |
返回不同值的计数 | ||
CRC32() |
计算循环冗余校验值 | ||
CUME_DIST() |
累积分布值 | ||
CURDATE() |
返回当前日期 | ||
CURRENT_DATE() , CURRENT_DATE |
CURDATE()的同义词 | ||
CURRENT_ROLE() |
返回当前活动角色 | ||
CURRENT_TIME() , CURRENT_TIME |
CURTIME()的同义词 | ||
CURRENT_TIMESTAMP() , CURRENT_TIMESTAMP |
NOW()的同义词 | ||
CURRENT_USER() , CURRENT_USER |
认证用户名称和主机名 | ||
CURTIME() |
返回当前时间 | ||
DATABASE() |
返回默认(当前)数据库名称 | ||
DATE() |
提取日期或日期时间表达式的日期部分 | ||
DATE_ADD() |
将时间值(间隔)添加到日期值 | ||
DATE_FORMAT() |
格式化指定的日期 | ||
DATE_SUB() |
从日期中减去时间值(间隔) | ||
DATEDIFF() |
减去两个日期 | ||
DAY() |
DAYOFMONTH()的同义词 | ||
DAYNAME() |
返回星期几的名称 | ||
DAYOFMONTH() |
返回月份的日期(0-31) | ||
DAYOFWEEK() |
返回参数的星期索引 | ||
DAYOFYEAR() |
返回年份的日期(1-366) | ||
DEFAULT() |
返回表列的默认值 | ||
DEGREES() |
将弧度转换为度数 | ||
DENSE_RANK() |
在其分区内当前行的排名,无间隔 | ||
DIV |
整数除法 | ||
ELT() |
返回索引号处的字符串 | ||
EXP() |
求幂 | ||
EXPORT_SET() |
返回一个字符串,对于值位中的每个位设置,您会得到一个打开字符串,对于每个未设置的位,您会得到一个关闭字符串 | ||
EXTRACT() |
提取日期的部分 | ||
ExtractValue() |
使用 XPath 表示法从 XML 字符串中提取值 | ||
FIELD() |
第一个参数在后续参数中的索引(位置) | ||
FIND_IN_SET() |
第一个参数在第二个参数中的索引(位置) | ||
FIRST_VALUE() |
窗口帧的第一行中的参数值 | ||
FLOOR() |
返回不大于参数的最大整数值 | ||
FORMAT() |
返回格式化为指定小数位数的数字 | ||
FORMAT_BYTES() |
将字节计数转换为带单位的值 | 8.0.16 | |
FORMAT_PICO_TIME() |
将皮秒时间转换为带单位的值 | 8.0.16 | |
FOUND_ROWS() |
对于带有 LIMIT 子句的 SELECT 语句,如果没有 LIMIT 子句,将返回的行数 | ||
FROM_BASE64() |
解码 base64 编码的字符串并返回结果 | ||
FROM_DAYS() |
将天数转换为日期 | ||
FROM_UNIXTIME() |
将 Unix 时间戳格式化为日期 | ||
GeomCollection() |
从几何体构造几何集合 | ||
GeometryCollection() |
从几何体构造几何集合 | ||
GET_DD_COLUMN_PRIVILEGES() |
仅供内部使用 | ||
GET_DD_CREATE_OPTIONS() |
仅供内部使用 | ||
GET_DD_INDEX_SUB_PART_LENGTH() |
仅供内部使用 | ||
GET_FORMAT() |
返回日期格式字符串 | ||
GET_LOCK() |
获取命名锁 | ||
GREATEST() |
返回最大的参数 | ||
GROUP_CONCAT() |
返回连接的字符串 | ||
group_replication_disable_member_action() |
为指定事件禁用成员操作 | 8.0.26 | |
group_replication_enable_member_action() |
为指定事件启用成员操作 | 8.0.26 | |
group_replication_get_communication_protocol() |
获取当前正在使用的组复制通信协议的版本 | 8.0.16 | |
group_replication_get_write_concurrency() |
获取当前为组设置的最大一致性实例数 | 8.0.13 | |
group_replication_reset_member_actions() |
将所有成员操作重置为默认值,并将配置版本号重置为 1 | 8.0.26 | |
group_replication_set_as_primary() |
将特定组成员设为主节点 | 8.0.29 | |
group_replication_set_communication_protocol() |
设置组复制通信协议要使用的版本 | 8.0.16 | |
group_replication_set_write_concurrency() |
设置可以并行执行的最大一致性实例数 | 8.0.13 | |
group_replication_switch_to_multi_primary_mode() |
将运行在单主模式下的组的模式更改为多主模式 | 8.0.13 | |
group_replication_switch_to_single_primary_mode() |
将运行在多主模式下的组的模式更改为单主模式 | 8.0.13 | |
GROUPING() |
区分超级聚合 ROLLUP 行和常规行 | ||
GTID_SUBSET() |
如果子集中的所有 GTID 也在集合中,则返回 true;否则返回 false。 | ||
GTID_SUBTRACT() |
返回集合中不在子集中的所有 GTID。 | ||
HEX() |
十六进制表示的十进制或字符串值 | ||
HOUR() |
提取小时 | ||
ICU_VERSION() |
ICU 库版本 | ||
IF() |
如果/否则结构 | ||
IFNULL() |
如果/否则结构中的空值 | ||
IN() |
值是否在一组值内 | ||
INET_ATON() |
返回 IP 地址的数值 | ||
INET_NTOA() |
从数值返回 IP 地址 | ||
INET6_ATON() |
返回 IPv6 地址的数值 | ||
INET6_NTOA() |
从数值返回 IPv6 地址 | ||
INSERT() |
在指定位置插入子字符串,最多指定字符数 | ||
INSTR() |
返回子字符串第一次出现的索引 | ||
INTERNAL_AUTO_INCREMENT() |
仅供内部使用 | ||
INTERNAL_AVG_ROW_LENGTH() |
仅供内部使用 | ||
INTERNAL_CHECK_TIME() |
仅供内部使用 | ||
INTERNAL_CHECKSUM() |
仅供内部使用 | ||
INTERNAL_DATA_FREE() |
仅供内部使用 | ||
INTERNAL_DATA_LENGTH() |
仅供内部使用 | ||
INTERNAL_DD_CHAR_LENGTH() |
仅供内部使用 | ||
INTERNAL_GET_COMMENT_OR_ERROR() |
仅供内部使用 | ||
INTERNAL_GET_ENABLED_ROLE_JSON() |
仅供内部使用 | 8.0.19 | |
INTERNAL_GET_HOSTNAME() |
仅供内部使用 | 8.0.19 | |
INTERNAL_GET_USERNAME() |
仅供内部使用 | 8.0.19 | |
INTERNAL_GET_VIEW_WARNING_OR_ERROR() |
仅供内部使用 | ||
INTERNAL_INDEX_COLUMN_CARDINALITY() |
仅供内部使用 | ||
INTERNAL_INDEX_LENGTH() |
仅供内部使用 | ||
INTERNAL_IS_ENABLED_ROLE() |
仅供内部使用 | 8.0.19 | |
INTERNAL_IS_MANDATORY_ROLE() |
仅供内部使用 | 8.0.19 | |
INTERNAL_KEYS_DISABLED() |
仅供内部使用 | ||
INTERNAL_MAX_DATA_LENGTH() |
仅供内部使用 | ||
INTERNAL_TABLE_ROWS() |
仅供内部使用 | ||
INTERNAL_UPDATE_TIME() |
仅供内部使用 | ||
INTERVAL() |
返回小于第一个参数的参数的索引 | ||
IS |
测试一个值是否为布尔值 | ||
IS_FREE_LOCK() |
检查指定的锁是否空闲 | ||
IS_IPV4() |
参数是否为 IPv4 地址 | ||
IS_IPV4_COMPAT() |
参数是否为 IPv4 兼容地址 | ||
IS_IPV4_MAPPED() |
参数是否为 IPv4 映射地址 | ||
IS_IPV6() |
参数是否为 IPv6 地址 | ||
IS NOT |
测试一个值是否为布尔值 | ||
IS NOT NULL |
非 NULL 值测试 | ||
IS NULL |
NULL 值测试 | ||
IS_USED_LOCK() |
检查指定的锁是否正在使用;如果是,则返回连接标识符 | ||
IS_UUID() |
参数是否为有效的 UUID | ||
ISNULL() |
测试参数是否为 NULL | ||
JSON_ARRAY() |
创建 JSON 数组 | ||
JSON_ARRAY_APPEND() |
向 JSON 文档追加数据 | ||
JSON_ARRAY_INSERT() |
插入到 JSON 数组中 | ||
JSON_ARRAYAGG() |
将结果集作为单个 JSON 数组返回 | ||
JSON_CONTAINS() |
JSON 文档是否包含特定路径处的对象 | ||
JSON_CONTAINS_PATH() |
JSON 文档是否在路径处包含任何数据 | ||
JSON_DEPTH() |
JSON 文档的最大深度 | ||
JSON_EXTRACT() |
从 JSON 文档中返回数据 | ||
JSON_INSERT() |
将数据插入 JSON 文档 | ||
JSON_KEYS() |
JSON 文档中的键数组 | ||
JSON_LENGTH() |
JSON 文档中的元素数量 | ||
JSON_MERGE() |
合并 JSON 文档,保留重复的键。已弃用的 JSON_MERGE_PRESERVE()的同义词 | 是 | |
JSON_MERGE_PATCH() |
合并 JSON 文档,替换重复键的值 | ||
JSON_MERGE_PRESERVE() |
合并 JSON 文档,保留重复的键 | ||
JSON_OBJECT() |
创建 JSON 对象 | ||
JSON_OBJECTAGG() |
将结果集作为单个 JSON 对象返回 | ||
JSON_OVERLAPS() |
比较两个 JSON 文档,如果它们有任何公共键值对或数组元素,则返回 TRUE(1),否则返回 FALSE(0) | 8.0.17 | |
JSON_PRETTY() |
以人类可读的格式打印 JSON 文档 | ||
JSON_QUOTE() |
引用 JSON 文档 | ||
JSON_REMOVE() |
从 JSON 文档中删除数据 | ||
JSON_REPLACE() |
替换 JSON 文档中的值 | ||
JSON_SCHEMA_VALID() |
针对 JSON 模式验证 JSON 文档;如果文档符合模式,则返回 TRUE/1,否则返回 FALSE/0 | 8.0.17 | |
JSON_SCHEMA_VALIDATION_REPORT() |
针对 JSON 模式验证 JSON 文档;返回 JSON 格式的验证结果报告,包括成功或失败以及失败原因 | 8.0.17 | |
JSON_SEARCH() |
JSON 文档中值的路径 | ||
JSON_SET() |
将数据插入 JSON 文档 | ||
JSON_STORAGE_FREE() |
部分更新后 JSON 列值的二进制表示中释放的空间 | ||
JSON_STORAGE_SIZE() |
用于存储 JSON 文档的二进制表示的空间 | ||
JSON_TABLE() |
将 JSON 表达式的数据作为关系表返回 | ||
JSON_TYPE() |
JSON 值的类型 | ||
JSON_UNQUOTE() |
取消 JSON 值的引号 | ||
JSON_VALID() |
JSON 值是否有效 | ||
JSON_VALUE() |
从 JSON 文档中提取路径指向的值;将该值作为 VARCHAR(512) 或指定类型返回 | 8.0.21 | |
LAG() |
分区内当前行后退行的参数值 | ||
LAST_DAY |
返回参数所在月份的最后一天 | ||
LAST_INSERT_ID() |
最后一次 INSERT 的 AUTOINCREMENT 列的值 | ||
LAST_VALUE() |
窗口帧中最后一行的参数值 | ||
LCASE() |
LOWER() 的同义词 | ||
LEAD() |
分区内当前行前导行的参数值 | ||
LEAST() |
返回最小的参数 | ||
LEFT() |
返回指定数量的最左侧字符 | ||
LENGTH() |
返回字符串的字节长度 | ||
LIKE |
简单的模式匹配 | ||
LineString() |
从 Point 值构造 LineString | ||
LN() |
返回参数的自然对数 | ||
LOAD_FILE() |
加载指定文件 | ||
LOCALTIME() , LOCALTIME |
NOW() 的同义词 | ||
LOCALTIMESTAMP , LOCALTIMESTAMP() |
NOW() 的同义词 | ||
LOCATE() |
返回子字符串第一次出现的位置 | ||
LOG() |
返回第一个参数的自然对数 | ||
LOG10() |
返回参数的以 10 为底的对数 | ||
LOG2() |
返回参数的以 2 为底的对数 | ||
LOWER() |
返回小写参数 | ||
LPAD() |
返回左侧填充了指定字符串的字符串参数 | ||
LTRIM() |
移除前导空格 | ||
MAKE_SET() |
返回一组逗号分隔的字符串,其中对应位在位中设置 | ||
MAKEDATE() |
从年份和一年中的天数创建日期 | ||
MAKETIME() |
从小时、分钟、秒创建时间 | ||
MASTER_POS_WAIT() |
阻塞,直到副本读取并应用到指定位置的所有更新 | 8.0.26 | |
MATCH() |
执行全文搜索 | ||
MAX() |
返回最大值 | ||
MBRContains() |
一个几何图形的 MBR 是否包含另一个几何图形的 MBR | ||
MBRCoveredBy() |
一个 MBR 是否被另一个覆盖 | ||
MBRCovers() |
一个 MBR 是否覆盖另一个 | ||
MBRDisjoint() |
两个几何图形的 MBR 是否不相交 | ||
MBREquals() |
两个几何图形的 MBR 是否相等 | ||
MBRIntersects() |
两个几何图形的 MBR 是否相交 | ||
MBROverlaps() |
两个几何图形的 MBR 是否重叠 | ||
MBRTouches() |
两个几何图形的 MBR 是否相接触 | ||
MBRWithin() |
一个几何图形的 MBR 是否在另一个几何图形的 MBR 内部 | ||
MD5() |
计算 MD5 校验和 | ||
MEMBER OF() |
如果第一个操作数与作为第二个操作数传递的 JSON 数组中的任何元素匹配,则返回 true(1),否则返回 false(0) | 8.0.17 | |
MICROSECOND() |
从参数返回微秒 | ||
MID() |
从指定位置开始返回子字符串 | ||
MIN() |
返回最小值 | ||
MINUTE() |
从参数返回分钟 | ||
MOD() |
返回余数 | ||
MONTH() |
返回传递日期的月份 | ||
MONTHNAME() |
返回月份的名称 | ||
MultiLineString() |
从 LineString 值构造多线 | ||
MultiPoint() |
从点值构造多点 | ||
MultiPolygon() |
从多边形值构造多边形 | ||
NAME_CONST() |
使列具有给定名称 | ||
NOT , ! |
反转值 | ||
NOT BETWEEN ... AND ... |
值是否不在一组值的范围内 | ||
NOT IN() |
值是否不在一组值内 | ||
NOT LIKE |
简单模式匹配的否定 | ||
NOT REGEXP |
REGEXP 的否定 | ||
NOW() |
返回当前日期和时间 | ||
NTH_VALUE() |
窗口帧的第 N 行参数值 | ||
NTILE() |
当前行在其分区内的桶号 | ||
NULLIF() |
如果 expr1 = expr2 则返回 NULL | ||
OCT() |
返回包含数字的八进制表示的字符串 | ||
OCTET_LENGTH() |
LENGTH() 的同义词 | ||
OR , || |
逻辑或 | ||
ORD() |
返回参数的最左字符的字符代码 | ||
PERCENT_RANK() |
百分比排名值 | ||
PERIOD_ADD() |
将一个周期添加到年-月 | ||
PERIOD_DIFF() |
返回两个周期之间的月数 | ||
PI() |
返回圆周率的值 | ||
Point() |
从坐标构造点 | ||
Polygon() |
从 LineString 参数构造多边形 | ||
POSITION() |
LOCATE() 的同义词 | ||
POW() |
返回参数的指定幂次方 | ||
POWER() |
返回参数的指定幂次方 | ||
PS_CURRENT_THREAD_ID() |
当前线程的性能模式线程 ID | 8.0.16 | |
PS_THREAD_ID() |
给定线程的性能模式线程 ID | 8.0.16 | |
QUARTER() |
返回日期参数的季度 | ||
QUOTE() |
为在 SQL 语句中使用而转义参数 | ||
RADIANS() |
将参数转换为弧度 | ||
RAND() |
返回一个随机浮点值 | ||
RANDOM_BYTES() |
返回一个随机字节向量 | ||
RANK() |
当前行在其分区内的排名,带有间隔 | ||
REGEXP |
字符串是否匹配正则表达式 | ||
REGEXP_INSTR() |
匹配正则表达式的子字符串的起始索引 | ||
REGEXP_LIKE() |
字符串是否匹配正则表达式 | ||
REGEXP_REPLACE() |
替换匹配正则表达式的子字符串 | ||
REGEXP_SUBSTR() |
返回匹配正则表达式的子字符串 | ||
RELEASE_ALL_LOCKS() |
释放所有当前命名的锁 | ||
RELEASE_LOCK() |
释放命名的锁 | ||
REPEAT() |
将字符串重复指定次数 | ||
REPLACE() |
替换指定字符串的出现次数 | ||
REVERSE() |
反转字符串中的字符 | ||
RIGHT() |
返回指定右侧字符数 | ||
RLIKE |
字符串是否匹配正则表达式 | ||
ROLES_GRAPHML() |
返回表示内存角色子图的 GraphML 文档 | ||
ROUND() |
四舍五入参数 | ||
ROW_COUNT() |
更新的行数 | ||
ROW_NUMBER() |
当前行在其分区内的编号 | ||
RPAD() |
将字符串重复指定次数 | ||
RTRIM() |
移除字符串末尾的空格 | ||
SCHEMA() |
DATABASE()的同义词 | ||
SEC_TO_TIME() |
将秒数转换为'hh:mm:ss'格式 | ||
SECOND() |
返回秒数 (0-59) | ||
SESSION_USER() |
USER()的同义词 | ||
SHA1() , SHA() |
计算 SHA-1 160 位校验和 | ||
SHA2() |
计算 SHA-2 校验和 | ||
SIGN() |
返回参数的符号 | ||
SIN() |
返回参数的正弦值 | ||
SLEEP() |
休眠指定秒数 | ||
SOUNDEX() |
返回一个 soundex 字符串 | ||
SOUNDS LIKE |
比较音频 | ||
SOURCE_POS_WAIT() |
阻塞直到复制品读取并应用到指定位置的所有更新 | 8.0.26 | |
SPACE() |
返回指定数量的空格字符串 | ||
SQRT() |
返回参数的平方根 | ||
ST_Area() |
返回多边形或多重多边形的面积 | ||
ST_AsBinary() , ST_AsWKB() |
从内部几何格式转换为 WKB | ||
ST_AsGeoJSON() |
从几何体生成 GeoJSON 对象 | ||
ST_AsText() , ST_AsWKT() |
从内部几何格式转换为 WKT | ||
ST_Buffer() |
返回距离给定几何体一定距离内的点的几何体 | ||
ST_Buffer_Strategy() |
为 ST_Buffer()生成策略选项 | ||
ST_Centroid() |
返回几何体的质心点 | ||
ST_Collect() |
将空间值聚合为集合 | 8.0.24 | |
ST_Contains() |
判断一个几何体是否包含另一个 | ||
ST_ConvexHull() |
返回几何体的凸包 | ||
ST_Crosses() |
一个几何体是否穿过另一个 | ||
ST_Difference() |
两个几何体的点集差 | ||
ST_Dimension() |
几何体的维度 | ||
ST_Disjoint() |
一个几何体是否与另一个不相交 | ||
ST_Distance() |
一个几何体到另一个几何体的距离 | ||
ST_Distance_Sphere() |
两个几何体在地球上的最小距离 | ||
ST_EndPoint() |
线串的终点 | ||
ST_Envelope() |
返回几何体的最小边界矩形 | ||
ST_Equals() |
一个几何体是否等于另一个 | ||
ST_ExteriorRing() |
返回多边形的外环 | ||
ST_FrechetDistance() |
一个几何体到另一个几何体的离散 Fréchet 距离 | 8.0.23 | |
ST_GeoHash() |
生成地理哈希值 | ||
ST_GeomCollFromText() , ST_GeometryCollectionFromText() , ST_GeomCollFromTxt() |
从 WKT 返回几何集合 | ||
ST_GeomCollFromWKB() , ST_GeometryCollectionFromWKB() |
从 WKB 返回几何集合 | ||
ST_GeometryN() |
从几何集合中返回第 N 个几何体 | ||
ST_GeometryType() |
返回几何类型的名称 | ||
ST_GeomFromGeoJSON() |
从 GeoJSON 对象生成几何体 | ||
ST_GeomFromText() , ST_GeometryFromText() |
从 WKT 返回几何体 | ||
ST_GeomFromWKB() , ST_GeometryFromWKB() |
从 WKB 返回几何体 | ||
ST_HausdorffDistance() |
一个几何体到另一个几何体的离散豪斯多夫距离 | 8.0.23 | |
ST_InteriorRingN() |
返回多边形的第 N 个内环 | ||
ST_Intersection() |
返回两个几何体的点集交集 | ||
ST_Intersects() |
判断一个几何体是否与另一个相交 | ||
ST_IsClosed() |
判断几何体是否封闭且简单 | ||
ST_IsEmpty() |
判断几何体是否为空 | ||
ST_IsSimple() |
判断几何体是否简单 | ||
ST_IsValid() |
判断几何体是否有效 | ||
ST_LatFromGeoHash() |
从 geohash 值返回纬度 | ||
ST_Latitude() |
返回 Point 的纬度 | 8.0.12 | |
ST_Length() |
返回 LineString 的长度 | ||
ST_LineFromText() , ST_LineStringFromText() |
从 WKT 构建 LineString | ||
ST_LineFromWKB() , ST_LineStringFromWKB() |
从 WKB 构建 LineString | ||
ST_LineInterpolatePoint() |
沿着 LineString 给定百分比的点 | 8.0.24 | |
ST_LineInterpolatePoints() |
沿着 LineString 给定百分比的点 | 8.0.24 | |
ST_LongFromGeoHash() |
从 geohash 值返回经度 | ||
ST_Longitude() |
返回 Point 的经度 | 8.0.12 | |
ST_MakeEnvelope() |
两点围成的矩形 | ||
ST_MLineFromText() , ST_MultiLineStringFromText() |
从 WKT 构建 MultiLineString | ||
ST_MLineFromWKB() , ST_MultiLineStringFromWKB() |
从 WKB 构建 MultiLineString | ||
ST_MPointFromText() , ST_MultiPointFromText() |
从 WKT 构建 MultiPoint | ||
ST_MPointFromWKB() , ST_MultiPointFromWKB() |
从 WKB 构建 MultiPoint | ||
ST_MPolyFromText() , ST_MultiPolygonFromText() |
从 WKT 构建 MultiPolygon | ||
ST_MPolyFromWKB() , ST_MultiPolygonFromWKB() |
从 WKB 构建 MultiPolygon | ||
ST_NumGeometries() |
返回几何集合中的几何图形数量 | ||
ST_NumInteriorRing() , ST_NumInteriorRings() |
返回多边形中的内部环数量 | ||
ST_NumPoints() |
返回线串中的点数 | ||
ST_Overlaps() |
一个几何图形是否与另一个重叠 | ||
ST_PointAtDistance() |
沿着线串给定距离的点 | 8.0.24 | |
ST_PointFromGeoHash() |
将 geohash 值转换为 POINT 值 | ||
ST_PointFromText() |
从 WKT 构造点 | ||
ST_PointFromWKB() |
从 WKB 构造点 | ||
ST_PointN() |
返回线串中第 N 个点 | ||
ST_PolyFromText() , ST_PolygonFromText() |
从 WKT 构造多边形 | ||
ST_PolyFromWKB() , ST_PolygonFromWKB() |
从 WKB 构造多边形 | ||
ST_Simplify() |
返回简化后的几何图形 | ||
ST_SRID() |
返回几何图形的空间参考系统 ID | ||
ST_StartPoint() |
线串的起始点 | ||
ST_SwapXY() |
返回 X/Y 坐标交换的参数 | ||
ST_SymDifference() |
返回两个几何图形的点集对称差 | ||
ST_Touches() |
一个几何图形是否与另一个相接触 | ||
ST_Transform() |
转换几何图形的坐标 | 8.0.13 | |
ST_Union() |
返回两个几何图形的点集并集 | ||
ST_Validate() |
返回经过验证的几何图形 | ||
ST_Within() |
一个几何图形是否在另一个内部 | ||
ST_X() |
返回点的 X 坐标 | ||
ST_Y() |
返回点的 Y 坐标 | ||
STATEMENT_DIGEST() |
计算语句摘要哈希值 | ||
STATEMENT_DIGEST_TEXT() |
计算规范化语句摘要 | ||
STD() |
返回总体标准偏差 | ||
STDDEV() |
返回总体标准偏差 | ||
STDDEV_POP() |
返回总体标准偏差 | ||
STDDEV_SAMP() |
返回样本标准偏差 | ||
STR_TO_DATE() |
将字符串转换为日期 | ||
STRCMP() |
比较两个字符串 | ||
SUBDATE() |
在使用三个参数调用时,DATE_SUB()的同义词 | ||
SUBSTR() |
返回指定的子字符串 | ||
SUBSTRING() |
返回指定的子字符串 | ||
SUBSTRING_INDEX() |
返回指定分隔符出现次数之前的字符串子串 | ||
SUBTIME() |
减去时间 | ||
SUM() |
返回总和 | ||
SYSDATE() |
返回函数执行时的时间 | ||
SYSTEM_USER() |
USER()的同义词 | ||
TAN() |
返回参数的正切 | ||
TIME() |
提取传递表达式的时间部分 | ||
TIME_FORMAT() |
格式化为时间 | ||
TIME_TO_SEC() |
返回转换为秒的参数 | ||
TIMEDIFF() |
减去时间 | ||
TIMESTAMP() |
使用单个参数,此函数返回日期或日期时间表达式;使用两个参数,返回参数的总和 | ||
TIMESTAMPADD() |
将间隔添加到日期时间表达式 | ||
TIMESTAMPDIFF() |
返回两个日期时间表达式的差异,使用指定的单位 | ||
TO_BASE64() |
返回转换为 base-64 字符串的参数 | ||
TO_DAYS() |
返回转换为天数的日期参数 | ||
TO_SECONDS() |
返回自公元 0 年以来的秒数转换为日期或日期时间参数 | ||
TRIM() |
移除前导和尾随空格 | ||
TRUNCATE() |
截断到指定的小数位数 | ||
UCASE() |
UPPER()的同义词 | ||
UNCOMPRESS() |
解压缩压缩的字符串 | ||
UNCOMPRESSED_LENGTH() |
返回压缩前字符串的长度 | ||
UNHEX() |
返回包含数字的十六进制表示的字符串 | ||
UNIX_TIMESTAMP() |
返回 Unix 时间戳 | ||
UpdateXML() |
返回替换的 XML 片段 | ||
UPPER() |
转换为大写 | ||
USER() |
客户端提供的用户名和主机名 | ||
UTC_DATE() |
返回当前的 UTC 日期 | ||
UTC_TIME() |
返回当前的 UTC 时间 | ||
UTC_TIMESTAMP() |
返回当前的 UTC 日期和时间 | ||
UUID() |
返回通用唯一标识符(UUID) | ||
UUID_SHORT() |
返回整数值通用标识符 | ||
UUID_TO_BIN() |
将字符串 UUID 转换为二进制 | ||
VALIDATE_PASSWORD_STRENGTH() |
确定密码强度 | ||
VALUES() |
定义在 INSERT 期间要使用的值 | ||
VAR_POP() |
返回总体标准方差 | ||
VAR_SAMP() |
返回样本方差 | ||
VARIANCE() |
返回总体标准方差 | ||
VERSION() |
返回指示 MySQL 服务器版本的字符串 | ||
WAIT_FOR_EXECUTED_GTID_SET() |
等待副本上执行给定的 GTIDs。 | ||
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() |
使用 WAIT_FOR_EXECUTED_GTID_SET() 。 |
8.0.18 | |
WEEK() |
返回周数 | ||
WEEKDAY() |
返回星期索引 | ||
WEEKOFYEAR() |
返回日期的日历周数(1-53) | ||
WEIGHT_STRING() |
返回字符串的权重字符串 | ||
XOR |
逻辑异或 | ||
YEAR() |
返回年份 | ||
YEARWEEK() |
返回年份和周数 | ||
| |
按位或 | ||
~ |
按位取反 | ||
名称 | 描述 | 引入版本 | 废弃版本 |