MySQL8-中文参考-二十-

MySQL8 中文参考(二十)

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

原文: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/charsetsshare/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_systemcharacter_set_servercharacter_set_client不同时,并且您手动输入字符(作为数据库对象标识符、列值或两者),这些字符可能会在客户端输出中显示不正确,或者输出本身可能格式不正确。在这种情况下,使用--default-character-set=*system_character_set*启动 mysql 客户端——即,将客户端字符集设置为与系统字符集匹配——应该可以解决问题。

12.16 MySQL 服务器区域设置支持

原文:dev.mysql.com/doc/refman/8.0/en/locale-support.html

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 意义

第十三章 数据类型

原文:dev.mysql.com/doc/refman/8.0/en/data-types.html

目录

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 适用于 TIMEDATETIMETIMESTAMP 类型,表示小数秒精度;即,小数秒部分的小数点后的位数。如果给定 fsp 值,则必须在范围 0 到 6 之间。值为 0 表示没有小数部分。如果省略,则默认精度为 0。(这与标准 SQL 默认值 6 不同,以与之前的 MySQL 版本兼容。)

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

13.1 数值数据类型

原文:dev.mysql.com/doc/refman/8.0/en/numeric-types.html

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, DECIMALNUMERIC),以及近似数值数据类型(FLOAT, REALDOUBLE PRECISION)。关键字INTINTEGER的同义词,关键字DECFIXEDDECIMAL的同义词。MySQL 将DOUBLE视为DOUBLE PRECISION的同义词(非标准扩展)。MySQL 还将REAL视为DOUBLE PRECISION的同义词(非标准变体),除非启用了REAL_AS_FLOAT SQL 模式。

BIT数据类型存储位值,并支持MyISAMMEMORYInnoDBNDB表。

有关 MySQL 如何处理超出范围值分配给列和在表达式评估期间的溢出的信息,请参阅第 13.1.7 节,“超出范围和溢出处理”。

有关数值数据类型的存储要求的信息,请参阅第 13.7 节,“数据类型存储要求”。

对于操作数值的函数描述,请参阅第 14.6 节,“数值函数和运算符”。对于数值操作数计算结果使用的数据类型取决于操作数的类型和执行的操作。更多信息,请参阅第 14.6.1 节,“算术运算符”。

13.1.1 数字数据类型语法

原文:dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html

对于整数数据类型,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 属性对于 FLOATDOUBLEDECIMAL(以及任何同义词)列已被弃用;您应该预期在未来的 MySQL 版本中将其移除。考虑为这些列使用简单的 CHECK 约束代替。

SERIALBIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE 的别名。

在整数列的定义中,SERIAL DEFAULT VALUENOT NULL AUTO_INCREMENT UNIQUE 的别名。

警告

当您在一个类型为 UNSIGNED 的整数值之间进行减法运算时,结果是无符号的,除非启用了 NO_UNSIGNED_SUBTRACTION SQL 模式。参见 第 14.10 节,“转换函数和运算符”。

  • BIT[(*M*)]

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

  • TINYINT[(*M*)] [UNSIGNED] [ZEROFILL]

    非常小的整数。有符号范围为 -128127。无符号范围为 0255

  • BOOL, BOOLEAN

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

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

    然而,值TRUEFALSE仅仅是10的别名,如下所示:

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

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

  • SMALLINT[(*M*)] [UNSIGNED] [ZEROFILL]

    一个小整数。有符号范围是-3276832767。无符号范围是065535

  • MEDIUMINT[(*M*)] [UNSIGNED] [ZEROFILL]

    一个中等大小的整数。有符号范围是-83886088388607。无符号范围是016777215

  • INT[(*M*)] [UNSIGNED] [ZEROFILL]

    一个正常大小的整数。有符号范围是-21474836482147483647。无符号范围是04294967295

  • INTEGER[(*M*)] [UNSIGNED] [ZEROFILL]

    这种类型是INT的同义词。

  • BIGINT[(*M*)] [UNSIGNED] [ZEROFILL]

    一个大整数。有符号范围是-92233720368547758089223372036854775807。无符号范围是018446744073709551615

    SERIALBIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的别名。

    关于BIGINT列,有一些需要注意的事项:

    • 所有算术运算都是使用有符号的BIGINTDOUBLE值进行的,因此除了使用位函数外,不应使用大于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-380,和1.175494351E-383.402823466E+38。这些是基于 IEEE 标准的理论极限。实际范围可能会略小,取决于您的硬件或操作系统。

    M是总位数,D是小数点后的位数。如果省略MD,则值将存储到硬件允许的极限。单精度浮点数精确到大约 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 仅使用此值来确定是否使用FLOATDOUBLE作为结果数据类型。如果p从 0 到 24,数据类型变为没有MD值的FLOAT。如果p从 25 到 53,数据类型变为没有MD值的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-3080,以及2.2250738585072014E-3081.7976931348623157E+308。这些是基于 IEEE 标准的理论极限。实际范围可能会略小,取决于您的硬件或操作系统。

    M是总位数,D是小数点后的位数。如果省略了MD,则值将存储到硬件允许的极限。双精度浮点数精确到大约 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 模式,则REALFLOAT的同义词,而不是DOUBLE

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

原文:dev.mysql.com/doc/refman/8.0/en/integer-types.html

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

表 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

原文:dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html

DECIMALNUMERIC类型存储精确的数值数据。当需要保留精确精度时,例如在货币数据中,使用这些类型。在 MySQL 中,NUMERIC被实现为DECIMAL,因此关于DECIMAL的以下说明同样适用于NUMERIC

MySQL 以二进制格式存储DECIMAL值。请参阅第 14.24 节,“精度数学”。

DECIMAL列声明中,通常会指定精度和标度。例如:

salary DECIMAL(5,2)

在这个例子中,5是精度,2是标度。精度表示存储值的有效数字的数量,而标度表示小数点后可以存储的数字的数量。

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

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

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

DECIMAL的最大数字位数为 65,但给定DECIMAL列的实际范围可以受到给定列的精度或标度的限制。当为这样的列分配一个具有比指定标度允许的更多小数位数的值时,该值将被转换为该标度。(具体行为取决于操作系统,但通常效果是截断为允许的数字位数。)

13.1.4 浮点类型(近似值) - FLOAT, DOUBLE

原文:dev.mysql.com/doc/refman/8.0/en/floating-point-types.html

FLOATDOUBLE 类型表示近似数值数据。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, “浮点值的问题”。

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

13.1.5 比特值类型 - BIT

原文:dev.mysql.com/doc/refman/8.0/en/bit-type.html

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) 的列具有 -3276832767 的通常 SMALLINT 范围,超出三位数允许范围的值将使用超过三位数的完整显示。

当与可选的(非标准的)ZEROFILL 属性一起使用时,默认的空格填充被零替换。例如,对于声明为 INT(4) ZEROFILL 的列,检索到的值为 5 会显示为 0005

注意

ZEROFILL 属性在涉及表达式或 UNION 查询的列中被忽略。

如果您在具有 ZEROFILL 属性的整数列中存储大于显示宽度的值,当 MySQL 为一些复杂的连接生成临时表时,可能会遇到问题。在这些情况下,MySQL 假定数据值适合列显示宽度内。

从 MySQL 8.0.17 开始,ZEROFILL 属性对于数字数据类型已被弃用,整数数据类型的显示宽度属性也是如此。您应该期望在未来的 MySQL 版本中删除对整数数据类型的 ZEROFILL 和显示宽度的支持。考虑使用其他方法来产生这些属性的效果。例如,应用程序可以使用 LPAD() 函数将数字零填充到所需的宽度,或者它们可以将格式化的数字存储在 CHAR 列中。

所有整数类型都可以具有可选的(非标准的)UNSIGNED属性。无符号类型可用于在列中仅允许非负数或在需要列的较大上限数值范围时使用。例如,如果INT列是UNSIGNED,则列范围的大小相同,但其端点向上移动,从-2147483648214748364704294967295

浮点和定点类型也可以是UNSIGNED。与整数类型一样,此属性防止负值存储在列中。与整数类型不同,列值的上限范围保持不变。从 MySQL 8.0.17 开始,对于FLOATDOUBLEDECIMAL(以及任何同义词)类型的列,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 版本,对于 FLOATDOUBLE 列,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 TABLELOAD DATAUPDATE 和多行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 日期和时间数据类型

原文:dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html

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 日期中的两位数年份

用于表示时间值的日期和时间数据类型是DATETIMEDATETIMETIMESTAMPYEAR。每种时间类型都有一系列有效值,以及一个“零”值,当您指定 MySQL 无法表示的无效值时可以使用。TIMESTAMPDATETIME 类型具有特殊的自动更新行为,详见第 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 允许您在DATEDATETIME列中存储日期,其中日期或月份和日期为零。这对于需要存储生日但可能不知道确切日期的应用程序非常有用。在这种情况下,您只需将日期存储为 '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

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

对于 DATEDATETIME 范围描述,“支持” 表示虽然较早的值可能有效,但不保证。

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

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

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

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

  • DATE

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

  • DATETIME[(*fsp*)]

    日期和时间的组合。支持范围为'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列到当前日期和时间可以使用DEFAULTON UPDATE列定义子句来指定,如第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”中所述。

  • TIMESTAMP[(*fsp*)]

    时间戳。范围为'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_TIMESTAMPON UPDATE CURRENT_TIMESTAMP属性分配给任何TIMESTAMP列。它们必须明确包含在列定义中。此外,任何未明确声明为NOT NULLTIMESTAMP允许NULL值。

    如果禁用explicit_defaults_for_timestamp,服务器处理TIMESTAMP如下:

    除非另有说明,否则表中的第一个TIMESTAMP列被定义为在未明确分配值的情况下自动设置为最近修改的日期和时间。这使得TIMESTAMP对于记录INSERTUPDATE操作的时间戳非常有用。您还可以通过将其分配为NULL值将任何TIMESTAMP列设置为当前日期和时间,除非已使用NULL属性定义允许NULL值。

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

  • TIME[(*fsp*)]

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

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

  • YEAR[(4)]

    以 4 位数字格式表示的年份。MySQL 以YYYY格式显示YEAR值,但允许使用字符串或数字将值分配给YEAR列。值显示为19012155,或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 日期、日期时间和时间戳类型

原文:dev.mysql.com/doc/refman/8.0/en/datetime.html

DATEDATETIMETIMESTAMP类型是相关的。本节描述它们的特征,它们的相似之处以及它们的区别。MySQL 以几种格式识别DATEDATETIMETIMESTAMP值,描述在第 11.1.3 节,“日期和时间文字”中。对于DATEDATETIME范围描述,“支持”表示尽管较早的值可能有效,但不能保证。

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。

DATETIMETIMESTAMP值可以包含高达微秒(6 位数字)精度的尾随小数秒部分。特别是,插入到DATETIMETIMESTAMP列中的值中的任何小数部分都会被存储而不是丢弃。包含小数部分时,这些值的格式为'*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 节,“时间值中的小数秒”。

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

MySQL 将TIMESTAMP值从当前时区转换为 UTC 进行存储,然后从 UTC 转换回当前时区进行检索。(对于DATETIME等其他类型,不会发生这种情况。)默认情况下,每个连接的当前时区是服务器的时区。时区可以根据每个连接设置。只要时区设置保持不变,您将获得与存储的相同值。如果存储了TIMESTAMP值,然后更改时区并检索该值,则检索到的值与存储的值不同。这是因为在两个方向的转换中没有使用相同的时区。当前时区可作为time_zone系统变量的值获得。有关更多信息,请参阅第 7.1.15 节,“MySQL 服务器时区支持”。

在 MySQL 8.0.19 及更高版本中,您可以在将TIMESTAMPDATETIME值插入表时指定时区偏移量。有关更多信息和示例,请参阅第 11.1.3 节,“日期和时间文字”。

如果 SQL 模式允许此转换,则无效的DATEDATETIMETIMESTAMP值将被转换为相应类型的“零”值('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 类型

原文:dev.mysql.com/doc/refman/8.0/en/time.html

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 年份类型

原文:dev.mysql.com/doc/refman/8.0/en/year.html

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值,范围为19012155,以及0000

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

  • 作为范围在'1901''2155'之间的 4 位数字字符串。

  • 作为范围在19012155之间的 4 位数字。

  • 作为范围在'0''99'之间的 1 位或 2 位字符串。MySQL 将范围在'0''69''70''99'之间的值转换为范围在2000206919701999之间的YEAR值。

  • 作为范围在099之间的 1 位或 2 位数字。MySQL 将范围在1697099之间的值转换为范围在2001206919701999之间的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

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

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

  • 自动初始化列对于未为该列指定值的插入行设置为当前时间戳。

  • 自动更新列在行中的任何其他列的值从当前值更改时,将自动更新为当前时间戳。如果所有其他列都设置为它们的当前值,则自动更新列保持不变。要防止自动更新列在其他列更改时更新,请明确将其设置为当前值。即使其他列不更改,也要更新自动更新列,请明确将其设置为应具有的值(例如,将其设置为CURRENT_TIMESTAMP)。

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

要指定自动属性,请在列定义中使用 DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP 子句。子句的顺序无关紧要。如果列定义中同时存在两者,则任何一个都可以先出现。任何 CURRENT_TIMESTAMP 的同义词都与 CURRENT_TIMESTAMP 具有相同的含义。这些同义词包括 CURRENT_TIMESTAMP()NOW()LOCALTIMELOCALTIME()LOCALTIMESTAMPLOCALTIMESTAMP()

使用DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP是特定于TIMESTAMPDATETIME 的。DEFAULT子句也可以用于指定常量(非自动)默认值(例如,DEFAULT 0DEFAULT '2000-01-01 00:00:00')。

注意

以下示例使用DEFAULT 0,这是一个可能会产生警告或错误的默认值,具体取决于是否启用了严格的 SQL 模式或 NO_ZERO_DATE SQL 模式。请注意,TRADITIONAL SQL 模式包括严格模式和 NO_ZERO_DATE。请参阅 第 7.1.11 节,“服务器 SQL 模式”。

TIMESTAMPDATETIME 列定义可以为默认值和自动更新值同时指定当前时间戳,其中一个指定当前时间戳,或者两者都不指定。不同列可以具有不同的自动属性组合。以下规则描述了可能性:

  • 同时使用DEFAULT CURRENT_TIMESTAMPON 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_TIMESTAMPON UPDATE CURRENT_TIMESTAMP。要抑制第一个 时间戳 列的自动属性,可以使用以下策略之一:

  • 启用 explicit_defaults_for_timestamp 系统变量。在这种情况下,指定自动初始化和更新的 DEFAULT CURRENT_TIMESTAMPON 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 列上有所不同。对于 t1ts1NOT NULL,将其赋值为 NULL 会将其设置为当前时间戳。对于 t2t3ts1 允许 NULL,将其赋值为 NULL 会将其设置为 NULL

  • t2t3ts1 的默认值上有所不同。对于 t2ts1 被定义为允许 NULL,因此在没有明确的 DEFAULT 子句的情况下,默认值也为 NULL。对于 t3ts1 允许 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,则必须明确插入与当前日期和时间对应的值。假设表t1t2具有以下定义:

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分配给当前时间戳,无论是否声明了NULLNOT NULL属性。要分配当前时间戳,请将列设置为CURRENT_TIMESTAMP或类似的同义词,如NOW()

13.2.6 时间值中的分数秒

原文:dev.mysql.com/doc/refman/8.0/en/fractional-seconds.html

MySQL 支持TIMEDATETIMETIMESTAMP值的分数秒,精度可达微秒(6 位数):

  • 要定义包含分数秒部分的列,请使用*type_name*(*fsp*)的语法,其中type_nameTIMEDATETIMETIMESTAMPfsp是分数秒精度。例如:

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

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

  • 将带有分数秒部分的TIMEDATETIMESTAMP值插入到具有较少分数位数但类型相同的列中会导致四舍五入。考虑以下创建和填充的表:

    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 使用哪种日历?

原文:dev.mysql.com/doc/refman/8.0/en/mysql-calendar.html

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 DATEDATETIME 值的转换前日期必须进行调整以弥补差异。重要的是要意识到,转换并不是在所有国家同时发生的,而且发生得越晚,丢失的天数就越多。例如,在英国,这发生在 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

在一定程度上,您可以将一个时间类型的值转换为另一个时间类型。但是,可能会对值进行一些更改或丢失信息。在所有情况下,时间类型之间的转换受到生成类型的有效值范围的限制。例如,尽管DATEDATETIMETIMESTAMP值都可以使用相同的格式集来指定,但这些类型的值范围并不相同。TIMESTAMP值不能早于1970年 UTC 或晚于'2038-01-19 03:14:07' UTC。这意味着像'1968-01-01'这样的日期,虽然作为DATEDATETIME值是有效的,但作为TIMESTAMP值是无效的,并转换为0

转换DATE值:

  • 转换为DATETIMETIMESTAMP值会添加一个时间部分'00:00:00',因为DATE值不包含时间信息。

  • 转换为TIME值没有用处;结果为'00:00:00'

转换DATETIMETIMESTAMP值:

  • 转换为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'时,转换为DATETIMETIMESTAMP值,结果分别为'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'

显式转换可用于覆盖隐式转换。例如,在比较DATEDATETIME值时,DATE值通过添加时间部分'00:00:00'被强制转换为DATETIME类型。要通过忽略DATETIME值的时间部分执行比较,可以使用CAST()函数如下方式:

*date_col* = CAST(*datetime_col* AS DATE)

TIMEDATETIME值转换为数值形式(例如,通过添加+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 位数年份

原文:dev.mysql.com/doc/refman/8.0/en/two-digit-years.html

具有 2 位数年份的日期值是模糊的,因为世纪未知。这些值必须被解释为 4 位数形式,因为 MySQL 在内部使用 4 位数存储年份。

对于DATETIMEDATETIMESTAMP类型,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 字符串数据类型

原文:dev.mysql.com/doc/refman/8.0/en/string-types.html

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 字符串数据类型语法

原文:dev.mysql.com/doc/refman/8.0/en/string-type-syntax.html

字符串数据类型包括CHAR, VARCHAR, BINARY, VARBINARY, BLOB, TEXT, ENUM, 和 SET

在某些情况下,MySQL 可能会将字符串列更改为与CREATE TABLEALTER 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 SETCOLLATE属性中的一个或两个缺失时,关于分配字符集和排序规则的规则在第 12.3.5 节,“列字符集和排序”中描述。

    CHARSETCHARACTER SET的同义词。

  • 为字符串数据类型指定 CHARACTER SET binary 属性会导致该列被创建为相应的二进制字符串数据类型:CHAR 变为 BINARYVARCHAR 变为 VARBINARYTEXT 变为 BLOB。对于 ENUMSET 数据类型,不会发生这种情况;它们将按声明创建。假设您使用以下定义指定一个表:

    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 替代。

字符列的比较和排序基于分配给列的校对规则。对于 CHARVARCHARTEXTENUMSET 数据类型,您可以声明一个带有二进制 (_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 模式。

    CHARCHARACTER的简写。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 值中删除尾随空格。

    VARCHARCHARACTER VARYING 的简写。NATIONAL VARCHAR 是定义 VARCHAR 列应使用某个预定义字符集的标准 SQL 方式。MySQL 使用 utf8mb3 作为这个预定义字符集。第 12.3.7 节,“国家字符集”。NVARCHARNATIONAL VARCHAR 的简写。

  • BINARY[(*M*)]

    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 字节长度前缀来存储,指示值中的字节数。

  • BLOB[(*M*)]

    最大长度为 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 x w) <= 1020,其中M是元素文字长度,w是字符集中最大长度字符所需的字节数。

  • SET('*value1*','*value2*',...) [字符集 *charset_name*] [校对 *collation_name*]

    一个集合。一个字符串对象,可以有零个或多个值,每个值必须从值列表'*value1*''*value2*'... SET中选择的值内部表示为整数。

    SET列最多可以有 64 个不同成员。

    单个SET元素的最大支持长度为M <= 255,且(M x w) <= 1020,其中M是元素文字长度,w是字符集中最大长度字符所需的字节数。

13.3.2 CHAR 和 VARCHAR 类型

原文:dev.mysql.com/doc/refman/8.0/en/char.html

CHARVARCHAR类型相似,但在存储和检索方式、最大长度以及是否保留尾随空格方面有所不同。

CHARVARCHAR类型声明的长度指示您希望存储的最大字符数。例如,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 模式,并且将值分配给超出列最大长度的CHARVARCHAR列,则该值将被截断以适应,并生成警告。对于非空格字符的截断,您可以通过使用严格的 SQL 模式来导致错误发生(而不是警告),并抑制值的插入。参见第 7.1.11 节,“服务器 SQL 模式”。

对于VARCHAR列,在插入之前会截断超出列长度的尾随空格,并生成警告,无论使用的 SQL 模式如何。对于CHAR列,无论使用的 SQL 模式如何,插入值时都会静默执行超出尾随空格的截断。

存储VARCHAR值时不会填充。在存储和检索值时,尾随空格会被保留,符合标准 SQL。

以下表格通过展示将各种字符串值存储到CHAR(4)VARCHAR(4)列中的结果(假设列使用单字节字符集如latin1)来说明CHARVARCHAR之间的差异。

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)

CHARVARCHARTEXT列中的值根据分配给列的字符集排序和比较。

MySQL 排序具有PAD SPACE填充属性,除了基于 UCA 9.0.0 及更高版本的 Unicode 排序具有NO PAD填充属性。 (参见第 12.10.1 节,“Unicode 字符集”).

要确定排序的填充属性,请使用INFORMATION_SCHEMA COLLATIONS表,该表具有一个PAD_ATTRIBUTE列。

对于非二进制字符串(CHARVARCHARTEXT值),字符串排序填充属性决定了在字符串末尾的尾随空格比较中的处理方式。NO PAD排序将尾随空格视为比较中的重要部分,就像任何其他字符一样。PAD SPACE排序将尾随空格视为比较中不重要的部分;字符串将在不考虑尾随空格的情况下进行比较。参见比较中的尾随空格处理。服务器 SQL 模式对于尾随空格的比较行为没有影响。

注意

有关 MySQL 字符集和排序的更多信息,请参见第十二章,“字符集、排序、Unicode”。有关存储要求的其他信息,请参见第 13.7 节,“数据类型存储要求”。

对于那些尾随填充字符被剥离或比较忽略它们的情况,如果一个列有一个需要唯一值的索引,插入到列中仅在尾随填充字符数量不同的值会导致重复键错误。例如,如果一个表包含'a',尝试存储'a '会导致重复键错误。

13.3.3 BINARY 和 VARBINARY 类型

原文:dev.mysql.com/doc/refman/8.0/en/binary-varbinary.html

BINARYVARBINARY 类型类似于 CHARVARCHAR,只是它们存储二进制字符串而不是非二进制字符串。也就是说,它们存储字节字符串而不是字符字符串。这意味着它们具有 binary 字符集和校对,比较和排序基于值中字节的数值。

BINARYVARBINARY 的最大长度与 CHARVARCHAR 的最大长度相同,只是 BINARYVARBINARY 的长度是以字节而不是字符计量的。

BINARYVARBINARY 数据类型与 CHAR BINARYVARCHAR BINARY 数据类型不同。对于后者,BINARY 属性不会导致列被视为二进制字符串列。相反,它会导致使用列字符集的二进制 (_bin) 校对(如果未指定列字符集,则使用表默认字符集),并且列本身存储非二进制字符字符串而不是二进制字节字符串。例如,如果默认字符集是 utf8mb4CHAR(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 模式,并且将值分配给超出列最大长度的 BINARYVARBINARY 列,则该值将被截断以适应,并生成警告。对于截断的情况,要导致发生错误(而不是警告)并阻止插入该值,请使用严格的 SQL 模式。请参见 Section 7.1.11, “Server SQL Modes”。

存储 BINARY 值时,它们会使用填充值右填充到指定长度。填充值为 0x00(零字节)。对于插入,值会使用 0x00 右填充,检索时不会删除尾随字节。在比较中,所有字节都是重要的,包括 ORDER BYDISTINCT 操作。0x00 和空格在比较中不同,0x00 排在空格之前。

例如:对于 BINARY(3) 列,'a ' 在插入时变为 'a \0''a\0' 在插入时变为 'a\0\0'。这两个插入值在检索时保持不变。

对于VARBINARY,插入时不进行填充,检索时不剥离任何字节。在比较中,所有字节都是重要的,包括ORDER BYDISTINCT操作。在比较中,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)

如果检索的值必须与存储时指定的值完全相同且没有填充,则最好使用VARBINARYBLOB数据类型之一。

注意

mysql客户端中,二进制字符串使用十六进制表示,取决于--binary-as-hex选项的值。有关该选项的更多信息,请参见 Section 6.5.1, “mysql — The MySQL Command-Line Client”。

13.3.4 BLOB 和 TEXT 类型

原文:dev.mysql.com/doc/refman/8.0/en/blob.html

BLOB是可以容纳可变数量数据的二进制大对象。四种BLOB类型分别是TINYBLOBBLOBMEDIUMBLOBLONGBLOB。它们仅在可以容纳的值的最大长度上有所不同。四种TEXT类型是TINYTEXTTEXTMEDIUMTEXTLONGTEXT。这些与四种BLOB类型对应,并具有相同的最大长度和存储要求。参见第 13.7 节,“数据类型存储要求”。

BLOB值被视为二进制字符串(字节字符串)。它们具有binary字符集和排序规则,比较和排序基于列值中字节的数值。TEXT值被视为非二进制字符串(字符字符串)。它们具有除binary之外的字符集,并且根据字符集的排序规则进行排序和比较。

如果未启用严格的 SQL 模式并且将值分配给超出列的最大长度的BLOBTEXT列,则该值将被截断以适应并生成警告。对于非空格字符的截断,您可以通过使用严格的 SQL 模式导致错误发生(而不是警告)并抑制值的插入。参见第 7.1.11 节,“服务器 SQL 模式”。

要插入TEXT列的值中多余的尾随空格截断总是生成警告,无论 SQL 模式如何。

对于TEXTBLOB列,在插入时不会填充,选择时也不会去除任何字节。

如果对TEXT列进行索引,索引条目比较在末尾填充空格。这意味着,如果索引需要唯一值,则对于仅在尾随空格数量上不同的值会导致重复键错误。例如,如果表包含'a',则尝试存储'a '会导致重复键错误。对于BLOB列则不是这样。

在大多数方面,您可以将BLOB列视为可以任意大的VARBINARY列。同样,您可以将TEXT列视为VARCHAR列。BLOBTEXTVARBINARYVARCHAR在以下方面有所不同:

  • 对于BLOBTEXT列上的索引,必须指定索引前缀长度。对于CHARVARCHAR,前缀长度是可选的。参见第 10.3.5 节,“列索引”。

  • BLOBTEXT列不能有DEFAULT值。

如果在TEXT数据类型中使用BINARY属性,则该列将被分配为列字符集的二进制(_bin)排序规则。

LONGLONG VARCHAR映射到MEDIUMTEXT数据类型。这是一个兼容性特性。

MySQL Connector/ODBC 将BLOB值定义为LONGVARBINARY,将TEXT值定义为LONGVARCHAR

因为BLOBTEXT值可能非常长,所以在使用它们时可能会遇到一些限制:

  • 在排序时只使用列的前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;
    
  • 在使用临时表处理的查询结果中存在BLOBTEXT列的实例会导致服务器在磁盘上而不是内存中使用表,因为MEMORY存储引擎不支持这些数据类型(参见第 10.4.4 节,“MySQL 中的内部临时表使用”)。使用磁盘会导致性能损失,因此只有在真正需要时才在查询结果中包含BLOBTEXT列。例如,避免使用SELECT *,它会选择所有列。

  • BLOBTEXT对象的最大大小由其类型确定,但实际上您可以在客户端和服务器之间传输的最大值取决于可用内存量和通信缓冲区的大小。您可以通过更改max_allowed_packet变量的值来更改消息缓冲区大小,但必须同时为服务器和客户端程序执行此操作。例如,mysqlmysqldump都允许您更改客户端端的max_allowed_packet值。请参阅第 7.1.1 节,“配置服务器”,第 6.5.1 节,“mysql — MySQL 命令行客户端”和第 6.5.4 节,“mysqldump — 数据库备份程序”。您可能还想比较数据包大小和您存储的数据对象的大小与存储要求的大小,参见第 13.7 节,“数据类型存储要求”

每个BLOBTEXT值在内部由单独分配的对象表示。这与所有其他数据类型形成对比,其他数据类型在打开表时为每列分配存储空间。

在某些情况下,将二进制数据(如媒体文件)存储在BLOBTEXT列中可能是可取的。您可能会发现 MySQL 的字符串处理函数在处理此类数据时非常有用。请参阅第 14.8 节,“字符串函数和运算符”。出于安全和其他原因,通常最好使用应用程序代码来处理此类数据,而不是给予应用程序用户FILE权限。您可以在 MySQL 论坛(forums.mysql.com/)讨论各种语言和平台的具体情况。

注意

mysql客户端中,二进制字符串以十六进制表示,具体取决于--binary-as-hex的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”。

13.3.5 ENUM 类型

原文:dev.mysql.com/doc/refman/8.0/en/enum.html

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'的枚举成员,但索引值为123

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')
);

我们强烈建议不要将数字用作枚举值,因为它不会节省适当TINYINTSMALLINT类型的存储空间,并且如果错误引用ENUM值,很容易混淆字符串和底层数值(可能不同)。如果将数字用作枚举值,请始终将其括在引号中。如果省略引号,则该数字被视为索引。请参阅枚举文字的处理以查看即使引用的数字也可能被错误地用作数值索引值的情况。

定义中的重复值会导致警告,如果启用了严格的 SQL 模式,则会导致错误。

13.3.6 SET类型

原文:dev.mysql.com/doc/refman/8.0/en/set.html

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 空间数据类型

原文:dev.mysql.com/doc/refman/8.0/en/spatial-types.html

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 表。对于索引空间列,MyISAMInnoDB 支持 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可以存储任何类型的几何值。其他单值类型(POINTLINESTRINGPOLYGON)将其值限制为特定的几何类型。

其他空间数据类型保存值的集合:

  • MULTIPOINT

  • MULTILINESTRING

  • MULTIPOLYGON

  • GEOMETRYCOLLECTION

GEOMETRYCOLLECTION可以存储任何类型的对象集合。其他集合类型(MULTIPOINTMULTILINESTRINGMULTIPOLYGON)将集合成员限制为具有特定几何类型的成员。

示例:要创建一个名为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 NULLSRID属性:

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具有PointCurveSurfaceGeometryCollection的子类:

  • Point代表零维对象。

  • Curve代表一维对象,具有子类LineString,子子类LineLinearRing

  • Surface设计用于二维对象,具有子类Polygon

  • GeometryCollection具有专门的零、一和二维集合类,分别命名为MultiPointMultiLineStringMultiPolygon,用于建模对应于PointsLineStringsPolygons的几何。MultiCurveMultiSurface被引入为概括集合接口以处理CurvesSurfaces的抽象超类。

GeometryCurveSurfaceMultiCurveMultiSurface被定义为不可实例化的类。它们为其子类定义了一组共同的方法,并且包含用于可扩展性的方法。

PointLineStringPolygonGeometryCollectionMultiPointMultiLineStringMultiPolygon是可实例化的类。

原文:dev.mysql.com/doc/refman/8.0/en/gis-class-geometry.html

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))
    
  • 值是简单还是非简单。类型为(LineStringMultiPointMultiLineString)的几何值要么是简单的,要么是非简单的。每种类型确定其自己的简单或非简单断言。

  • 值是闭合还是未闭合。类型为(LineStringMultiString)的几何值要么是闭合的,要么是未闭合的。每种类型确定其自己的闭合或未闭合断言。

  • 该值是还是非空。如果几何图形没有任何点,则为空。空几何图形的外部、内部和边界未定义(即,它们由 NULL 值表示)。空几何图形被定义为始终简单且面积为 0。

  • 它的维度。一个几何图形可以具有维度为−1、0、1 或 2:

    • −1 代表空几何图形。

    • 0 代表长度和面积均为零的几何图形。

    • 1 代表具有非零长度和零面积的几何图形。

    • 2 代表具有非零面积的几何图形。

    Point 对象的维度为零。LineString 对象的维度为 1。Polygon 对象的维度为 2。MultiPointMultiLineStringMultiPolygon 对象的维度与它们所包含的元素的维度相同。

原文:dev.mysql.com/doc/refman/8.0/en/gis-class-point.html

13.4.2.3 点类

一个Point是表示坐标空间中单个位置的几何体。

Point示例

  • 想象一幅世界地图,上面标注着许多城市。一个Point对象可以代表每个城市。

  • 在城市地图上,一个Point对象可以代表一个公交车站。

Point属性

  • X 坐标值。

  • Y 坐标值。

  • Point被定义为零维几何体。

  • 一个Point的边界是空集。

原文:dev.mysql.com/doc/refman/8.0/en/gis-class-curve.html

13.4.2.4 Curve 类

一个Curve是一维几何体,通常由一系列点表示。特定的Curve子类定义了点之间的插值类型。Curve是一个不可实例化的类。

Curve属性

  • 一个Curve具有其点的坐标。

  • 一个Curve被定义为一维几何体。

  • 如果一个Curve不通过同一点两次,则它是简单的,但如果起点和终点相同,则曲线仍然可以是简单的。

  • 如果一个Curve的起点等于终点,则该Curve是闭合的。

  • 闭合Curve的边界为空。

  • 非闭合Curve的边界由其两个端点组成。

  • 一个简单且闭合的CurveLinearRing

原文: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

原文:dev.mysql.com/doc/refman/8.0/en/gis-class-surface.html

13.4.2.6 Surface 类

一个Surface是一个二维几何体。它是一个不可实例化的类。它唯一可实例化的子类是Polygon

Surface属性

  • 一个Surface被定义为一个二维几何体。

  • OpenGIS 规范将简单的Surface定义为一个几何体,由一个与单个外部边界和零个或多个内部边界相关联的“补丁”组成。

  • 一个简单Surface的边界是与其外部和内部边界对应的一组闭合曲线。

原文:dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html

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 是一个包含零个或多个任意类别几何体的集合几何体。

GeomCollectionGeometryCollection 是同义词,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是一个规则的、闭合的点集。

  • 一个具有多个PolygonMultiPolygon具有不连通的内部。MultiPolygon内部的连通分量数量等于MultiPolygon中的Polygon值数量。

MultiPolygon属性

  • 一个MultiPolygon是一个二维几何体。

  • 一个MultiPolygon的边界是一组闭合曲线(LineString值),对应于其Polygon元素的边界。

  • MultiPolygon边界中的每个Curve都在一个Polygon元素的边界中。

  • 每个Polygon元素边界中的每个Curve都在MultiPolygon的边界中。

13.4.3 支持的空间数据格式

原文:dev.mysql.com/doc/refman/8.0/en/gis-data-formats.html

用于在查询中表示几何对象的两种标准空间数据格式:

  • 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 来表示 PointLineStringPolygonMultiPointMultiLineStringMultiPolygonGeometryCollection

  • Point 值具有 X 和 Y 坐标,每个坐标表示为双精度值。

更复杂的几何值的 WKB 值具有更复杂的数据结构,详细信息请参阅 OpenGIS 规范。

内部几何存储格式

MySQL 使用 4 个字节来指示 SRID,然后是值的 WKB 表示。有关 WKB 格式的描述,请参阅熟知二进制(WKB)格式。

对于 WKB 部分,这些是适用于 MySQL 的特定考虑因素:

  • 字节顺序指示符字节为 1,因为 MySQL 将几何值存储为小端值。

  • MySQL 支持 PointLineStringPolygonMultiPointMultiLineStringMultiPolygonGeometryCollection 几何类型。不支持其他几何类型。

  • 只有 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 TABLEALTER TABLE。空间列支持MyISAMInnoDBNDBARCHIVE表。另请参阅有关在第 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

对于MyISAMInnoDB表,包含空间数据的列中的搜索操作可以使用SPATIAL索引进行优化。最典型的操作包括:

  • 点查询,搜索包含给定点的所有对象

  • 区域查询,搜索与给定区域重叠的所有对象

MySQL 在空间列上使用具有二次分裂的 R-Tree来构建SPATIAL索引。SPATIAL索引是使用几何图形的最小外接矩形(MBR)构建的。对于大多数几何图形,MBR 是一个围绕几何图形的最小矩形。对于水平或垂直线串,MBR 是一个退化为线串的矩形。对于点,MBR 是一个退化为点的矩形。

也可以在空间列上创建普通索引。在非SPATIAL索引中,必须为除POINT列之外的任何空间列声明前缀。

MyISAMInnoDB都支持SPATIAL和非SPATIAL索引。其他存储引擎支持非SPATIAL索引,如第 15.1.15 节,“CREATE INDEX 语句”中所述。

13.4.10 创建空间索引

原文:dev.mysql.com/doc/refman/8.0/en/creating-spatial-indexes.html

对于InnoDBMyISAM表,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 TABLEDROP INDEX

  • 使用ALTER TABLE

    ALTER TABLE geom DROP INDEX g;
    
  • 使用DROP INDEX

    DROP INDEX g ON geom;
    

例如:假设一个表geom包含超过 32,000 个几何图形,这些图形存储在类型为GEOMETRY的列g中。该表还有一个AUTO_INCREMENTfid用于存储对象 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 数据类型

原文:dev.mysql.com/doc/refman/8.0/en/json.html

  • 创建 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 文档所需的空间大致与 LONGBLOBLONGTEXT 相同;有关更多信息,请参见 第 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_docjson_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。(对于asciiutf8mb3字符集中的字符串,不需要转换,因为asciiutf8mb3utf8mb4的子集。)

作为使用文字字符串编写 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 的nulltruefalse字面量,它们必须始终以小写形式编写:

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

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

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

JSON 字面量的大小写敏感性与 SQL 的NULLTRUEFALSE字面量的大小写敏感性不同,后者可以以任何大小写形式编写:

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

有时可能需要或希望将引号字符("')插入 JSON 文档中。假设为此示例,您想要插入一些包含表示关于 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*,其中MN分别是 JSON 数组中一系列元素的第一个和最后一个索引。N必须大于MM必须大于或等于 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 文本应使用asciiutf8mb3utf8mb4字符集进行编码。其他字符编码将被隐式强制转换为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 的DATETIMETIMESTAMP类型,则如果它们表示相同的时间点,则它们相等。

  • TIME

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

  • DATE

    较早日期在较近日期之前。

  • ARRAY

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

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

    例子:

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

    JSON 中的 false 文字小于 JSON 中的 true 文字。

  • OBJECT

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

    例子:

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

    两个不相等的对象的顺序是未指定的,但是确定的。

  • STRING

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

    例子:

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

    这种排序等同于具有utf8mb4_bin排序规则的 SQL 字符串的排序。因为utf8mb4_bin有一个二进制排序规则,所以 JSON 值的比较是区分大小写的:

    "A" < "a"
    
  • INTEGERDOUBLE

    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 字符类型(utf8mb4utf8mb3ascii 字符串被解析为 JSON 值。 JSON 值被序列化为utf8mb4字符串。
其他字符类型 其他字符编码会隐式转换为utf8mb4,并按照该字符类型描述的方式处理。 JSON 值被序列化为utf8mb4字符串,然后转换为其他字符编码。结果可能无意义。
NULL 结果为 JSON 类型的NULL值。 不适用。
几何类型 几何值通过调用 ST_AsGeoJSON() 转换为 JSON 文档。 非法操作。解决方法:将 CAST(*json_val* AS CHAR) 的结果传递给 ST_GeomFromGeoJSON()
所有其他类型 结果为由单个标量值组成的 JSON 文档。 如果 JSON 文档由目标类型的单个标量值组成且该标量值可以转换为目标类型,则成功。否则,返回NULL并产生警告。

对于 JSON 值,ORDER BYGROUP BY 遵循以下原则:

  • 标量 JSON 值的排序使用与前述讨论相同的规则。

  • 对于升序排序,SQL NULL 排在所有 JSON 值之前,包括 JSON 的 null 字面量;对于降序排序,SQL NULL 排在所有 JSON 值之后,包括 JSON 的 null 字面量。

  • JSON 值的排序键受 max_sort_length 系统变量的值限制,因此仅在首个 max_sort_length 字节之后有差异的键将被视为相等。

  • 非标量值的排序目前不受支持,会出现警告。

对于排序,将 JSON 标量转换为其他本机 MySQL 类型可能是有益的。例如,如果名为jdoc的列包含具有由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 数据类型默认值

原文:dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html

数据类型规范可以具有显式或隐式默认值。

数据类型规范中的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())
);

例外情况是,对于TIMESTAMPDATETIME列,您可以指定CURRENT_TIMESTAMP函数作为默认值,而无需括号。请参阅第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”。

只有将BLOBTEXTGEOMETRYJSON数据类型写为表达式时,才能为其分配默认值,即使表达式值是字面值:

  • 这是允许的(将字面默认指定为表达式):

    CREATE TABLE t2 (b BLOB DEFAULT ('abc'));
    
  • 这会产生一个错误(未将字面默认指定为表达式):

    CREATE TABLE t2 (b BLOB DEFAULT 'abc');
    

表达式默认值必须遵守以下规则。如果表达式包含不允许的结构,则会发生错误。

  • 字面常量、内置函数(确定性和非确定性)和运算符是允许的。

  • 子查询、参数、变量、存储函数和可加载函数不被允许。

  • 表达式默认值不能依赖于具有AUTO_INCREMENT属性的列。

  • 一个列的表达式默认值可以引用其他表列,但是不能引用生成列或具有表达式默认值的列,除非这些列在表定义中出现在前面。也就是说,表达式默认值不能包含对生成列或具有表达式默认值的列的前向引用。

    排序约束也适用于使用ALTER TABLE重新排序表列。如果结果表会有一个包含对生成列或具有表达式默认值的列的前向引用的表达式默认值,则该语句将失败。

注意

如果表达式默认值的任何组件依赖于 SQL 模式,除非在所有使用期间 SQL 模式相同,否则对表的不同使用可能会导致不同的结果。

对于CREATE TABLE ... LIKECREATE TABLE ... SELECT,目标表会保留原始表的表达式默认值。

如果表达式默认值引用了一个非确定性函数,任何导致表达式被评估的语句对于基于语句的复制都是不安全的。这包括诸如INSERTUPDATE之类的语句。在这种情况下,如果二进制日志记录被禁用,该语句将正常执行。如果启用了二进制日志记录并且binlog_format设置为STATEMENT,则该语句将被记录并执行,但会向错误日志写入警告消息,因为复制从机可能会发散。当binlog_format设置为MIXEDROW时,该语句将正常执行。

在插入新行时,具有表达式默认值的列的默认值可以通过省略列名或将列指定为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。例外是,对于TIMESTAMPDATETIME列,你可以指定CURRENT_TIMESTAMP作为默认值。参见 第 13.2.5 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”。

BLOBTEXTGEOMETRYJSON 数据类型不能被分配默认值。

如果默认值计算结果的数据类型与声明的列类型不同,根据通常的 MySQL 类型转换规则会发生隐式强制转换到声明的类型。参见 第 14.3 节,“表达式评估中的类型转换”。

隐式默认处理

如果数据类型规范中不包含显式DEFAULT值,MySQL 将确定默认值如下:

如果列可以接受NULL作为值,则该列将定义为带有显式DEFAULT NULL子句的列。

如果列不能接受NULL作为值,MySQL 将定义不带显式DEFAULT子句的列。

对于没有显式DEFAULT子句的NOT NULL列的数据输入,如果INSERTREPLACE语句不包含该列的值,或者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 字节,即使存储引擎能够支持更大的行也是如此。这个数字不包括BLOBTEXT列,这些列只对这个大小贡献了 9 到 12 个字节。对于BLOBTEXT数据,信息存储在内存的不同区域中,而不是行缓冲区。不同的存储引擎根据它们用于处理相应类型的方法以不同的方式处理这些数据的分配和存储。有关更多信息,请参见第十八章,替代存储引擎和第 10.4.7 节,“表列计数和行大小限制”。

InnoDB 表存储要求

有关InnoDB表的存储要求,请参见第 17.10 节“InnoDB 行格式”。

NDB 表存储要求

重要提示

NDB表使用 4 字节对齐;所有NDB数据存储都是 4 字节的倍数。因此,在NDB表中,通常需要 15 字节的列值需要 16 字节。例如,在NDB表中,TINYINTSMALLINTMEDIUMINTINTEGERINT)列类型每个记录需要 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

日期和时间类型存储需求

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

数据类型 MySQL 5.6.4 之前所需存储空间 MySQL 5.6.4 及以后所需存储空间
YEAR 1 字节 1 字节
DATE 3 字节 3 字节
TIME 3 字节 3 字节 + 分数秒存储
DATETIME 8 字节 5 字节 + 分数秒存储
TIMESTAMP 4 字节 4 字节 + 分数秒存储

截至 MySQL 5.6.4 版本,YEARDATE 的存储方式保持不变。然而,TIMEDATETIMETIMESTAMP 的表示方式有所不同。DATETIME 被更有效地打包,非分数部分只需 5 个字节,而不是 8 个字节,而且所有三部分都有一个分数部分,根据存储值的分数秒精度,需要从 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 个字节。TIMETIME(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字节来存储值,再加上三个字节来存储值的长度。

要计算存储特定CHARVARCHARTEXT列值所需的字节数,必须考虑用于该列的字符集以及值是否包含多字节字符。特别是在使用 UTF-8 Unicode 字符集时,必须记住并非所有字符使用相同数量的字节。utf8mb3utf8mb4字符集分别可以每个字符需要最多三个和四个字节。有关不同类别utf8mb3utf8mb4字符所使用的存储的详细信息,请参见第 12.9 节“Unicode 支持”。

VARCHARVARBINARYBLOBTEXT 类型是可变长度类型。对于每种类型,存储需求取决于以下因素:

  • 列值的实际长度

  • 列的最大可能长度

  • 列使用的字符集,因为某些字符集包含多字节字符

例如,VARCHAR(255) 列可以容纳最大长度为 255 个字符的字符串。假设该列使用 latin1 字符集(每个字符一个字节),实际所需存储空间是字符串的长度(L),再加上一个字节来记录字符串的长度。对于字符串 'abcd'L 为 4,存储需求为五个字节。如果相同列改为使用 ucs2 双字节字符集,则存储需求为 10 个字节:'abcd' 的长度为八个字节,列需要两个字节来存储长度,因为最大长度大于 255(最多 510 个字节)。

可存储在 VARCHARVARBINARY 列中的有效最大 字节数 受限于 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, BLOBJSON 列在 NDB 存储引擎中实现方式不同,其中列中的每一行由两个独立部分组成。其中一个是固定大小的(TEXTBLOB 为 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 不会为 TINYBLOBTINYTEXT 列值单独存储 blob 部分。

可以使用 NDB_COLUMN 在创建或更改父表时在列注释中将 NDB blob 列的 blob 部分大小增加到最大值 13948。在 NDB 8.0.30 及更高版本中,还可以使用 NDB_TABLE 在列注释中设置 TEXTBLOBJSON 列的内联大小。有关更多信息,请参见 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 列的存储需求大致与 LONGBLOBLONGTEXT 列相同;也就是说,JSON 文档所占用的空间大致与存储在这些类型列中的文档的字符串表示相同。然而,由于存储在 JSON 文档中的各个值的二进制编码,包括用于查找的元数据和字典,会带来一些额外开销。例如,存储在 JSON 文档中的字符串需要额外的 4 到 10 字节的存储空间,取决于字符串的长度以及存储它的对象或数组的大小。

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

13.8 选择适合列的正确类型

原文:dev.mysql.com/doc/refman/8.0/en/choosing-types.html

为了最佳存储,您应该尽量在所有情况下使用最精确的类型。例如,如果整数列用于范围在199999之间的值,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)

第十四章 函数和运算符

原文:dev.mysql.com/doc/refman/8.0/en/functions.html

目录

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 BYHAVING子句中,在SELECTDELETEUPDATE语句的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, &#124;&#124; 逻辑或
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() 返回年份和周数
&#124; 按位或
~ 按位取反
名称 描述 引入版本 废弃版本
posted @ 2024-06-23 00:40  绝不原创的飞龙  阅读(88)  评论(0)    收藏  举报