原文:docs.oracle.com/javase/tutorial/reallybigindex.html
14.9.3 使用查询扩展进行全文搜索
原文:dev.mysql.com/doc/refman/8.0/en/fulltext-query-expansion.html
全文搜索支持查询扩展(特别是它的变体,“盲查询扩展”)。当搜索短语太短时,这非常有用,这意味着用户依赖于全文搜索引擎所没有的隐性知识。例如,搜索“database”的用户实际上可能会匹配“database”,并希望返回“MySQL”、“Oracle”、“DB2”、“RDBMS”等术语。这是隐性知识。
通过在搜索短语后添加“WITH QUERY EXPANSION”或“IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION”来启用盲目查询扩展(也称为自动相关性反馈)。这是通过执行两次搜索来实现的。第二次搜索找到与第一次搜索中最相关的文档串联的原始搜索短语。因此,如果这些文档之一包含单词“database”和“MySQL”,则第二次搜索将返回单词“MySQL”,即使它不包含单词“database”也会搜索包含的文档。以下示例说明了这种差异。
mysql SELECT * FROM 文章
WHERE MATCH(标题、正文)
AGAINST(自然语言模式“数据库”);
+—————-+——————–+———————— — ——————+
| 标题|
+—————-+——————–+———————— — ——————+
| 1 | MySQL 教程| DBMS 代表数据库。
| 5 | MySQL 和YourSQL 的比较
+—————-+——————–+———————— — ——————+
2 行组(0.00 秒)
mysql SELECT * FROM 文章
WHERE MATCH(标题、正文)
AGAINST(带有查询扩展的“数据库”);
+—–+——————–+——————– ———————————-+
| 标题|
+—–+——————–+——————– ———————————-+
| 5 | MySQL 和YourSQL 的比较
| 1 | MySQL 教程| DBMS 代表数据库。
| 3 | 优化MySQL
| 6 | MySQL 安全
| 2 | 如何有效使用MySQL |
| 4 | 1001 个MySQL 技巧1\\.不要以root 身份运行mysqld。
+—–+——————–+——————– ———————————-+
6 行组(0.00 秒)
另一个例子是,当用户不知道如何拼写“Magret”并搜索Giorgio Simeno 的有关Maigret 的书时。如果不扩展查询,搜索“梅格雷与不情愿的证人”只会找到“梅格雷与不情愿的证人”。此外,使用查询扩展的搜索将在第二次搜索中找到包含单词“Maigret”的所有书籍。
消息
仅当搜索短语较短时才应使用盲目查询扩展,因为它往往会返回不相关的文档并显着增加噪音。
14.9.4 全文停用词
原文:dev.mysql.com/doc/refman/8.0/en/fulltext-stopwords.html
使用服务器的字符集和排序规则(character_set_server 和collation_server 系统变量的值)加载停用词列表,并使用全文查询进行搜索。如果用于全文索引或搜索的停用词文件或列的字符集或排序规则与character_set_server 或collation_server 不同,则停用词搜索中可能会出现错误命中或未命中。
停用词搜索的大小写敏感性取决于服务器的排序规则。例如,如果排序规则为utf8mb4_0900_ai_ci,则搜索不区分大小写,但如果排序规则为utf8mb4_0900_as_cs 或utf8mb4_bin,则搜索区分大小写。
InnoDB 搜索索引的停用词
MyISAM 搜索索引停用词
InnoDB 搜索索引的停用词
InnoDB 的默认停用词列表相对较短,因为来自技术、文学和其他来源的文档经常使用短单词作为关键字或重要短语。例如,如果您搜索“to be or not to be”,您可以期望得到合理的结果,而不是忽略所有这些词。
要查看默认的InnoDB 停用词列表,请查询信息架构中的INNODB_FT_DEFAULT_STOPWORD 表。
mysql SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;
+——+
| 价值|
+——+
|
关于|
|
|是|
| 作为|
| 德|
| 成为|
| 通过|
| com |
| 德|
| zh |
|对于|
| 来自|
|如何|
| 我|
| 德|
|是|
|它|
| 拉|
| 的|
| 至|
| 或|
|它|
|
|这个|
| 至|
| 是|
| 什么|
| 什么时候|
| 地点|
|谁|
| 会|
| 与
| 和|
|
| www |
+——+
36 行组(0.00 秒)
要为所有InnoDB 表定义自己的停用词列表,请定义一个与INNODB_FT_DEFAULT_STOPWORD 表结构相同的表,设置其停用词,并在创建全文索引之前将innodb_ft_server_stopword_table 选项的值设置为*db_name* 格式。 /。 *表名*的值。停用词列表必须有一个名为value 的VARCHAR 列。以下示例显示了InnoDB 的新全局停用词列表的创建和配置。
— 创建一个新的停用词表
mysql 创建表my_stopwords(value VARCHAR(30)) ENGINE=INNODB;
查询正常,0 行受影响(0.01 秒)
— 插入一个停用词(为简单起见,本例中使用了一个停用词)
mysql INSERT INTO my_stopwords(value) VALUES (\’以实玛利\’);
查询正常,1 行受影响(0.00 秒)
— 创建表
mysql CREATE TABLE 起始行数(
id INT UNSIGNED AUTO_INCRMENT NOT NULL 主键,
开头行TEXT(500),
作者VARCHAR(200),
标题VARCHAR(200)
) 引擎=InnoDB;
查询正常,0 行受影响(0.01 秒)
— 将数据插入表中。
mysql 插入起始行(起始行,作者,标题)值
(“请叫我以实玛利”、“赫尔曼·梅尔维尔”、“白鲸”)、
(“我听到天空中有一声尖叫”、“托马斯·品钦”、“万有引力彩虹”)
(“我是隐形人”、“拉尔夫·埃里森”、“隐形人”)
(“现在在哪里?现在是谁?什么时候?”,“塞缪尔·贝克特”,“难以言表”),
(“这是一见钟情”,“约瑟夫·海勒”,“第二十二条军规”),
(“或多或少,这一切都发生了。”,“库尔特·冯内古特”,“五号屠宰场”),
(“达洛维夫人说她会自己买花。”,“弗吉尼亚·伍尔夫”,“达洛维夫人”),
(“燃烧真好”、“雷·布拉德伯里”、“华氏451 度”);
查询正常,8 行受影响(0.00 秒)
记录: 8 重复: 0 警告: 0
— 将innodb_ft_server_stopword_table 选项设置为新的停用词表。
mysql SET GLOBAL innodb_ft_server_stopword_table=\’test/my_stopwords\’;
查询正常,0 行受影响(0.00 秒)
— 创建全文索引(如果未定义FTS_DOC_ID 列,则重建表)。
mysql 创建全文索引idx ON 起始行(opening_line);
查询正常,0 行受影响,1 条警告(1.17 秒)
记录: 0 重复: 0 警告: 1
查询信息模式INNODB_FT_INDEX_TABLE 表,查看是否出现指定的停用词(“Ishmael”)。
消息
默认情况下,长度小于3个字符或大于84个字符的单词不会出现在InnoDB全文搜索索引中。最大和最小字长值可以通过innodb_ft_max_token_size和innodb_ft_min_token_size变量进行配置。此默认行为不适用于ngram 解析器插件。 ngram 令牌的大小由ngram_token_size 选项定义。
mysql SET GLOBAL innodb_ft_aux_table=\’test/opening_lines\’;
查询正常,0 行受影响(0.00 秒)
mysql 从INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE LIMIT 15 中选择单词;
+———-+
| 话|
+———-+
|对面|
| 全部|
| 烧毁|
| 购买|
|致电|
| 来|
| 达洛维|
| 第一|
| 鲜花|
| 发生了|
| 我自己|
| 隐形|
| 少|
| 爱|
| 男人|
+———-+
15 行组(0.00 秒)
要为每个表创建停用词列表,请在创建全文索引之前创建一个额外的停用词表,并使用innodb_ft_user_stopword_table 选项指定要使用的停用词表。
MyISAM搜索索引的停用词
如果character_set_server为ucs2、utf16、utf16le或utf32,则使用latin1加载和搜索停用词文件。
要覆盖MyISAM 表的默认停用词列表,请设置ft_stopword_file 系统变量。 (请参阅服务器系统变量。)变量值必须是包含停用词列表的文件的路径名,或者是空字符串以禁用停用词过滤。服务器在数据目录中搜索文件,除非指定了指定不同目录的绝对路径名。更改此变量的值或停用词文件的内容后,重新启动服务器并重建FULLTEXT 索引。
停用词列表是自由格式的,停用词由非字母数字字符(例如换行符、空格和逗号)分隔。下划线字符(_) 和单引号(\’) 是单词的一部分。停用词列表字符集是服务器的默认字符集。请参见第12.3.2 节“服务器字符集和排序规则”。
以下列表显示了MyISAM 搜索索引的默认停用词。在MySQL 源代码发行版中,此列表位于storage/myisam/ft_static.c 文件中。
根据它,a 可以做的几乎超过
因此,实际上在那之后
再次强调,并非一切都被允许
已经允许几乎独自一人
还有,我总是在里面
任何一位
无论如何,任何人,任何事,无论如何
看起来离任何地方都很远
周围没有什么合适的
放在一边询问并提出相关问题
现在可以在非常偏远的地方使用
因为它将会是,它将会是,它将会是
我相信前面、前面、后面
接下来加上比最好更好的
虽然比两者都短,
嗯,就在这里。
不能引起原因
肯定会明显改变
结果,com来了
考虑考虑包括包括
目前没有对应的课程
虽然没写,但是写的很清楚。
我不会做任何不同的事
中间不要向下转
每项教育,例如八项之一
特别是在其他地方完全足够
诸如此类,每次
每个人,每个人,无处不在
确实如此,除了少数例外
继第一个5 个之后的第5 个
继续上一页上一页上一页
再拿4个
给定
去去去得到
几乎没有任何问候。
没有
嘿你好请帮助我
她在这里,她在这里,她将会在这里
你好她自己在这里
他自己,如果可以的话,直到现在
怎么样,但我愿意
如果我被忽视我会的
当然很快
显示显示显示内部范围
进去不是
就这样了,就这样了
本身只是继续维护
我知道我知道最近我知道
稍后,稍后,稍后,至少更少
至少给个赞吧
可能几乎看不见
ltd可能主要是更多
也就是说,与此同时,它可能只是
更多,并且在大多数情况下更多
也就是说,我必须自己命名
几乎是必需的需求
n
eeds neither never nevertheless new
next nine no nobody non
none noone nor normally not
nothing novel now nowhere obviously
of off often oh ok
okay old on once one
ones only onto or other
others otherwise ought our ours
ourselves out outside over overall
own particular particularly per perhaps
placed please plus possible presumably
probably provides que quite qv
rather rd re really reasonably
regarding regardless regards relatively respectively
right said same saw say
saying says second secondly see
seeing seem seemed seeming seems
seen self selves sensible sent
serious seriously seven several shall
she should shouldn\’t since six
so some somebody somehow someone
something sometime sometimes somewhat somewhere
soon sorry specified specify specifying
still sub such sup sure
t\’s take taken tell tends
th than thank thanks thanx
that that\’s thats the their
theirs them themselves then thence
there there\’s thereafter thereby therefore
therein theres thereupon these they
they\’d they\’ll they\’re they\’ve think
third this thorough thoroughly those
though three through throughout thru
thus to together too took
toward towards tried tries truly
try trying twice two un
under unfortunately unless unlikely until
unto up upon us use
used useful uses using usually
value various very via viz
vs want wants was wasn\’t
way we we\’d we\’ll we\’re
we\’ve welcome well went were
weren\’t what what\’s whatever when
whence whenever where where\’s whereafter
whereas whereby wherein whereupon wherever
whether which while whither who
who\’s whoever whole whom whose
why will willing wish with
within without won\’t wonder would
wouldn\’t yes yet you you\’d
you\’ll you\’re you\’ve your yours
yourself yourselves zero
14.9.5 全文限制
原文:dev.mysql.com/doc/refman/8.0/en/fulltext-restrictions.html
仅支持对InnoDB和MyISAM表进行全文搜索。
不支持对分区表进行全文搜索。请参阅第 26.6 节“分区的限制和限制”。
大多数多字节字符集都可以与全文搜索一起使用。唯一的例外是对于 Unicode,可以使用utf8mb3或utf8mb4字符集,但不能使用ucs2字符集。虽然无法使用ucs2列上的FULLTEXT索引,但可以在没有此类索引的ucs2列上执行IN BOOLEAN MODE搜索。
utf8mb3的备注也适用于utf8mb4,ucs2的备注也适用于utf16、utf16le和utf32。
汉语和日语等表意语言没有词分隔符。因此,内置全文解析器无法确定这些语言中单词的起始和结束位置。
提供了支持中文、日文和韩文(CJK)的基于字符的 ngram 全文解析器,以及支持日文的基于词的 MeCab 解析器插件,可用于InnoDB和MyISAM表。
尽管支持在单个表中使用多个字符集,但FULLTEXT索引中的所有列必须使用相同的字符集和排序规则。
MATCH()列列表必须与表的某个FULLTEXT索引定义中的列列表完全匹配,除非这个MATCH()在MyISAM表上是IN BOOLEAN MODE。对于MyISAM表,布尔模式搜索可以在非索引列上进行,尽管可能会很慢。
AGAINST()的参数必须是在查询评估期间保持不变的字符串值。例如,表列就不符合要求,因为每行可能不同。
截至 MySQL 8.0.28 版本,MATCH()的参数不能使用汇总列。
对于FULLTEXT搜索,索引提示比非FULLTEXT搜索更受限制。请参阅第 10.9.4 节“索引提示”。
对于InnoDB,涉及具有全文索引的列的所有 DML 操作(INSERT、UPDATE、DELETE)在事务提交时处理。例如,对于INSERT操作,插入的字符串被标记化并分解为单词。当事务提交时,这些单词将被添加到全文索引表中。因此,全文搜索仅返回已提交的数据。
‘%’ 字符不是全文搜索的支持通配符字符。
14.9.6 调整 MySQL 全文搜索
原文:dev.mysql.com/doc/refman/8.0/en/fulltext-fine-tuning.html
MySQL 的全文搜索功能有很少的用户可调参数。如果你有 MySQL 源码分发,你可以更多地控制全文搜索行为,因为一些更改需要修改源代码。参见 Section 2.8, “从源代码安装 MySQL”。
全文搜索经过精心调整以提高效果。在大多数情况下修改默认行为实际上可能会降低效果。不要修改 MySQL 源码,除非你知道你在做什么。
本节描述的大多数全文变量必须在服务器启动时设置。更改它们需要重新启动服务器;不能在服务器运行时修改。
一些变量更改需要重建表中的FULLTEXT索引。如何执行此操作将在本节后面给出。
配置最小和最大单词长度
配置自然语言搜索阈值
修改布尔全文搜索运算符
字符集修改
重建 InnoDB 全文索引
优化 InnoDB 全文索引
重建 MyISAM 全文索引
配置最小和最大单词长度
要索引的单词的最小和最大长度由 innodb_ft_min_token_size 和 innodb_ft_max_token_size(对于InnoDB搜索索引)以及 ft_min_word_len 和 ft_max_word_len(对于MyISAM)定义。
注意
最小和最大单词长度全文参数不适用于使用 ngram 解析器创建的FULLTEXT索引。ngram 标记大小由 ngram_token_size 选项定义。
在更改任何这些选项后,重新构建你的FULLTEXT索引以使更改生效。例如,要使两个字符的单词可搜索,你可以在选项文件中加入以下行:
[mysqld]
innodb_ft_min_token_size=2
ft_min_word_len=2
然后重新启动服务器并重建您的FULLTEXT索引。对于MyISAM表,请注意以下有关重建MyISAM全文索引的说明中关于myisamchk的备注。
配置自然语言搜索阈值
对于MyISAM搜索索引,自然语言搜索的 50%阈值取决于所选择的特定加权方案。要禁用它,请查找storage/myisam/ftdefs.h中的以下行:
#define GWS_IN_USE GWS_PROB
将该行更改为:
#define GWS_IN_USE GWS_FREQ
然后重新编译 MySQL。在这种情况下,无需重建索引。
注意
通过进行此更改,您严重降低了 MySQL 为MATCH()函数提供充分相关性值的能力。如果您真的需要搜索这样的常见词,最好使用IN BOOLEAN MODE进行搜索,该模式不遵守 50%的阈值。
修改布尔全文搜索运算符
要更改在MyISAM表上用于布尔全文搜索的运算符,请设置ft_boolean_syntax系统变量。(InnoDB没有相应的设置。)此变量可以在服务器运行时更改,但您必须具有足够的权限来设置全局系统变量(请参阅第 7.1.9.1 节,“系统变量权限”)。在这种情况下,不需要重建索引。
字符集修改
对于内置全文解析器,您可以通过以下列表中描述的几种方式更改被视为单词字符的字符集。进行修改后,重新为包含任何FULLTEXT索引的每个表重建索引。假设您希望将连字符字符(‘-’)视为单词字符。使用以下方法之一:
修改 MySQL 源代码:在storage/innobase/handler/ha_innodb.cc(对于InnoDB)或storage/myisam/ftdefs.h(对于MyISAM)中查看true_word_char()和misc_word_char()宏。将\’-\’添加到其中一个宏中,然后重新编译 MySQL。
修改字符集文件:这不需要重新编译。true_word_char()宏使用“字符类型”表来区分字母和数字与其他字符。 您可以编辑一个字符集 XML 文件中的<ctype><map>数组的内容,以指定\’-\’是一个“字母”。然后使用给定的字符集为您的FULLTEXT索引。有关<ctype><map>数组格式的信息,请参阅第 12.13.1 节,“字符定义数组”。
为使用索引列的字符集添加新的排序规则,并修改列以使用该排序规则。有关添加排序规则的一般信息,请参见 Section 12.14, “Adding a Collation to a Character Set”。有关全文索引的特定示例,请参见 Section 14.9.7, “Adding a User-Defined Collation for Full-Text Indexing”。
重建 InnoDB 全文索引
要使更改生效,必须在修改以下任一全文索引变量后重建FULLTEXT索引:innodb_ft_min_token_size; innodb_ft_max_token_size; innodb_ft_server_stopword_table; innodb_ft_user_stopword_table; innodb_ft_enable_stopword; ngram_token_size。修改innodb_ft_min_token_size、innodb_ft_max_token_size或ngram_token_size需要重新启动服务器。
要为InnoDB表重建FULLTEXT索引,请使用ALTER TABLE与DROP INDEX和ADD INDEX选项,以删除并重新创建每个索引。
优化 InnoDB 全文索引
在具有全文索引的表上运行OPTIMIZE TABLE会重建全文索引,删除已删除的文档 ID,并在可能的情况下 consololidating 多个相同单词的条目。
要优化全文索引,请启用innodb_optimize_fulltext_only并运行OPTIMIZE TABLE。
mysql> set GLOBAL innodb_optimize_fulltext_only=ON;
Query OK, 0 rows affected (0.01 sec)
mysql> OPTIMIZE TABLE opening_lines;
+——————–+———-+———-+———-+
| Table | Op | Msg_type | Msg_text |
+——————–+———-+———-+———-+
| test.opening_lines | optimize | status | OK |
+——————–+———-+———-+———-+
1 row in set (0.01 sec)
为了避免在大表上进行全文索引的长时间重建,您可以使用innodb_ft_num_word_optimize选项分阶段执行优化。innodb_ft_num_word_optimize选项定义了每次运行OPTIMIZE TABLE时优化的单词数。默认设置为 2000,这意味着每次运行OPTIMIZE TABLE时会优化 2000 个单词。后续的OPTIMIZE TABLE操作将从前一个OPTIMIZE TABLE操作结束的地方继续。
重建 MyISAM 全文索引
如果您修改影响索引的全文变量(ft_min_word_len、ft_max_word_len或ft_stopword_file),或者更改停用词文件本身,则在进行更改并重新启动服务器后,必须重建您的FULLTEXT索引。
要重建MyISAM表的FULLTEXT索引,只需进行QUICK修复操作即可:
mysql> REPAIR TABLE *tbl_name* QUICK;
或者,如刚才所述使用ALTER TABLE。在某些情况下,这可能比修复操作更快。
每个包含任何FULLTEXT索引的表必须按照刚才展示的方式进行修复。否则,对该表的查询可能会产生不正确的结果,并且对表的修改会导致服务器将表视为损坏并需要修复。
如果您使用myisamchk执行修改MyISAM表索引的操作(如修复或分析),FULLTEXT索引将使用默认的全文参数值进行重建,包括最小单词长度、最大单词长度和停用词文件,除非您另有规定。这可能导致查询失败。
问题出现在这些参数仅由服务器知道。它们不存储在MyISAM索引文件中。如果您已修改了服务器使用的最小或最大单词长度或停用词文件值,为了避免问题,请为myisamchk指定与mysqld使用的相同的ft_min_word_len、ft_max_word_len和ft_stopword_file值。例如,如果您将最小单词长度设置为 3,您可以像这样使用myisamchk修复表:
myisamchk –recover –ft_min_word_len=3 *tbl_name*.MYI
为了确保myisamchk和服务器使用相同的全文参数值,将每个值放在选项文件的[mysqld]和[myisamchk]部分中:
[mysqld]
ft_min_word_len=3
[myisamchk]
ft_min_word_len=3
用于MyISAM表索引修改的一种替代方法是使用REPAIR TABLE、ANALYZE TABLE、OPTIMIZE TABLE或ALTER TABLE语句。这些语句由服务器执行,服务器知道要使用的正确全文参数值。
14.9.7 为全文索引添加用户定义的排序规则
原文:dev.mysql.com/doc/refman/8.0/en/full-text-adding-collation.html
警告
用户定义的排序规则已被弃用;您应该期望在未来的 MySQL 版本中删除对它们的支持。从 MySQL 8.0.33 开始,服务器对任何 SQL 语句中使用 COLLATE *user_defined_collation* 都会发出警告;当服务器以 –collation-server 设置为用户定义的排序规则的名称时,也会发出警告。
本节描述如何为使用内置全文解析器进行全文搜索添加用户定义的排序规则。示例排序规则类似于 latin1_swedish_ci,但将 \’-\’ 字符视为字母而不是标点符号,以便将其索引为单词字符。有关添加排序规则的一般信息在 Section 12.14, “Adding a Collation to a Character Set” 中给出;假定您已经阅读并熟悉了涉及的文件。
要为全文索引添加排序规则,请使用以下过程。这里的说明添加了一个简单字符集的排序规则,如 Section 12.14, “Adding a Collation to a Character Set” 中所讨论的,可以使用描述字符集属性的配置文件来创建。对于像 Unicode 这样的复杂字符集,请使用描述字符集属性的 C 源文件创建排序规则。
在 Index.xml 文件中添加一个排序规则。用户定义的排序规则的允许 ID 范围在 Section 12.14.2, “Choosing a Collation ID” 中给出。ID 必须未使用,因此如果系统中已经使用了 ID 1025,则选择一个不同的值。
<charset name=\”latin1\”>
…
<collation name=\”latin1_fulltext_ci\” id=\”1025\”/>
</charset>
在 latin1.xml 文件中声明排序规则的排序顺序。在这种情况下,排序顺序可以从 latin1_swedish_ci 复制:
<collation name=\”latin1_fulltext_ci\”>
<map>
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
</map>
</collation>
修改 latin1.xml 中的 ctype 数组。将对应于 \’-\’ 字符的代码 0x2D(即连字符的代码)的值从 10(标点符号)更改为 01(大写字母)。在下面的数组中,这是从下面第四行开始,从末尾数第三个值的元素。
<ctype>
<map>
00
20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
48 10 10 10 10 10 10 10 10 10 10 10 10 *01* 10 10
84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
10 00 10 02 10 10 10 10 10 10 01 10 01 00 01 00
00 10 10 10 10 10 10 10 10 10 02 10 02 00 02 01
48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02
</map>
</ctype>
重新启动服务器。
要使用新的排序规则,将其包含在要使用它的列的定义中:
mysql> DROP TABLE IF EXISTS t1;
Query OK, 0 rows affected (0.13 sec)
mysql> CREATE TABLE t1 (
a TEXT CHARACTER SET latin1 COLLATE latin1_fulltext_ci,
FULLTEXT INDEX(a)
) ENGINE=InnoDB;
Query OK, 0 rows affected (0.47 sec)
测试排序规则,以验证连字符被视为单词字符:
mysql> INSERT INTO t1 VALUEs (\’—-\’),(\’….\’),(\’abcd\’);
Query OK, 3 rows affected (0.22 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t1 WHERE MATCH a AGAINST (\’—-\’ IN BOOLEAN MODE);
+——+
| a |
+——+
| —- |
+——+
1 row in set (0.00 sec)
14.9.8 ngram 全文解析器
原文:dev.mysql.com/doc/refman/8.0/en/fulltext-search-ngram.html
内置的 MySQL 全文解析器使用单词之间的空格作为分隔符来确定单词的起始和结束位置,这在处理不使用单词分隔符的表意语言时存在限制。为了解决这个限制,MySQL 提供了一个支持中文、日文和韩文(CJK)的 ngram 全文解析器。ngram 全文解析器支持与InnoDB和MyISAM一起使用。
注意
MySQL 还为日语提供了一个 MeCab 全文解析器插件,将文档标记为有意义的单词。有关更多信息,请参见第 14.9.9 节,“MeCab 全文解析器插件”。
ngram 是从给定文本序列中的连续*n个字符序列。ngram 解析器将文本序列标记为连续的n个字符序列。例如,您可以使用 ngram 全文解析器为不同的n*值对“abcd”进行标记。
n=1: \’a\’, \’b\’, \’c\’, \’d\’
n=2: \’ab\’, \’bc\’, \’cd\’
n=3: \’abc\’, \’bcd\’
n=4: \’abcd\’
ngram 全文解析器是一个内置的服务器插件。与其他内置的服务器插件一样,在服务器启动时会自动加载。
描述在第 14.9 节,“全文搜索函数”中的全文搜索语法适用于 ngram 解析器插件。本节描述了解析行为的差异。除了最小和最大单词长度选项(innodb_ft_min_token_size,innodb_ft_max_token_size,ft_min_word_len,ft_max_word_len)之外,也适用于与全文搜索相关的配置选项。
配置 ngram Token 大小
ngram 解析器具有默认的 ngram token 大小为 2(bigram)。例如,使用大小为 2 的 token,ngram 解析器将字符串“abc def”解析为四个 token:“ab”,“bc”,“de”和“ef”。
ngram token 大小可通过ngram_token_size配置选项进行配置,最小值为 1,最大值为 10。
通常,ngram_token_size 被设置为您想要搜索的最大标记的大小。如果您只打算搜索单个字符,请将 ngram_token_size 设置为 1。较小的标记大小会产生较小的全文搜索索引,并且搜索速度更快。如果您需要搜索由多个字符组成的单词,请相应地设置 ngram_token_size。例如,“生日快乐”在简体中文中是“Happy Birthday”,其中“生日”是“birthday”,“快乐”翻译为“happy”。要搜索这样的两个字符单词,将 ngram_token_size 设置为 2 或更高的值。
作为只读变量,ngram_token_size 只能作为启动字符串的一部分或在配置文件中设置:
启动字符串:
mysqld –ngram_token_size=2
配置文件:
[mysqld]
ngram_token_size=2
注意
对于使用 ngram 解析器的 FULLTEXT 索引,以下最小和最大单词长度配置选项将被忽略:innodb_ft_min_token_size, innodb_ft_max_token_size, ft_min_word_len, 和 ft_max_word_len。
创建使用 ngram 解析器的 FULLTEXT 索引
要创建使用 ngram 解析器的 FULLTEXT 索引,请在 CREATE TABLE, ALTER TABLE, 或 CREATE INDEX 中指定 WITH PARSER ngram。
以下示例演示了创建具有 ngram FULLTEXT 索引的表,插入示例数据(简体中文文本)以及在信息模式 INNODB_FT_INDEX_CACHE 表中查看标记化数据。
mysql> USE test;
mysql> CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT (title,body) WITH PARSER ngram
) ENGINE=InnoDB CHARACTER SET utf8mb4;
mysql> SET NAMES utf8mb4;
INSERT INTO articles (title,body) VALUES
(\’数据库管理\’,\’在本教程中我将向你展示如何管理数据库\’),
(\’数据库应用开发\’,\’学习开发数据库应用程序\’);
mysql> SET GLOBAL innodb_ft_aux_table=\”test/articles\”;
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE ORDER BY doc_id, position;
要向现有表添加 FULLTEXT 索引,可以使用 ALTER TABLE 或 CREATE INDEX。例如:
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT
) ENGINE=InnoDB CHARACTER SET utf8mb4;
ALTER TABLE articles ADD FULLTEXT INDEX ft_index (title,body) WITH PARSER ngram;
# Or:
CREATE FULLTEXT INDEX ft_index ON articles (title,body) WITH PARSER ngram;
ngram 解析器空格处理
ngram 解析器在解析时消除空格。例如:
“ab cd” 被解析为 “ab”, “cd”
“a bc” 被解析为 “bc”
ngram 解析器停用词处理
内置的 MySQL 全文解析器将单词与停用词列表中的条目进行比较。如果一个词等于停用词列表中的条目,则该词将从索引中排除。对于 ngram 解析器,停用词处理方式不同。它不是排除等于停用词列表中条目的标记,而是排除包含停用词的标记。例如,假设ngram_token_size=2,包含“a,b”的文档被解析为“a,”和“,b”。如果逗号(“,”)被定义为停用词,那么“a,”和“,b”都将因为包含逗号而被排除在索引之外。
默认情况下,ngram 解析器使用默认停用词列表,其中包含一组英语停用词。对于适用于中文、日文或韩文的停用词列表,您必须创建自己的停用词列表。有关创建停用词列表的信息,请参见第 14.9.4 节,“全文停用词”。
长度大于ngram_token_size的停用词将被忽略。
ngram 解析器术语搜索
对于自然语言模式搜索,搜索词被转换为 ngram 词的并集。例如,字符串“abc”(假设ngram_token_size=2)被转换为“ab bc”。给定两个文档,一个包含“ab”,另一个包含“abc”,搜索词“ab bc”匹配两个文档。
对于布尔模式搜索,搜索词被转换为 ngram 短语搜索。例如,字符串’abc’(假设ngram_token_size=2)被转换为’“ab bc”‘。给定两个文档,一个包含’ab’,另一个包含’abc’,搜索短语’“ab bc”\’仅匹配包含’abc’的文档。
ngram 解析器通配符搜索
因为 ngram FULLTEXT索引仅包含 ngrams,并不包含有关术语开头的信息,通配符搜索可能会返回意外结果。以下行为适用于使用 ngram FULLTEXT搜索索引进行通配符搜索的情况:
如果通配符搜索的前缀项短于 ngram 标记大小,查询将返回所有包含以前缀项开头的 ngram 标记的索引行。例如,假设ngram_token_size=2,搜索“a*”将返回所有以“a”开头的行。
如果通配符搜索的前缀项长于 ngram 标记大小,则前缀项被转换为 ngram 短语,通配符操作符被忽略。例如,假设ngram_token_size=2,一个“abc*”通配符搜索被转换为“ab bc”。
ngram 解析器短语搜索
短语搜索被转换为 ngram 短语搜索。例如,搜索短语“abc”被转换为“ab bc”,返回包含“abc”和“ab bc”的文档。
搜索短语“abc def”被转换为“ab bc de ef”,返回包含“abc def”和“ab bc de ef”的文档。不返回包含“abcdef”的文档。
14.9.9 MeCab 全文解析器插件
原文:dev.mysql.com/doc/refman/8.0/en/fulltext-search-mecab.html
MySQL 内置的全文解析器使用单词之间的空格作为分隔符来确定单词的起始和结束位置,这在处理不使用单词分隔符的表意语言时存在限制。为了解决这个问题,MySQL 为日语提供了 MeCab 全文解析器插件。MeCab 全文解析器插件支持与InnoDB和MyISAM一起使用。
注意
MySQL 还提供了支持日语的 ngram 全文解析器插件。有关更多信息,请参见第 14.9.8 节“ngram 全文解析器”。
MeCab 全文解析器插件是用于日语的全文解析器插件,将文本序列标记为有意义的单词。例如,MeCab 将“データベース管理”(“数据库管理”)标记为“データベース”(“数据库”)和“管理”(“管理”)。相比之下,ngram 全文解析器将文本标记为连续的*n个字符序列,其中n*表示 1 到 10 之间的数字。
除了将文本标记为有意义的单词外,MeCab 索引通常比 ngram 索引小,并且 MeCab 全文搜索通常更快。一个缺点是与 ngram 全文解析器相比,MeCab 全文解析器可能需要更长的时间来标记文档。
第 14.9 节“全文搜索函数”中描述的全文搜索语法适用于 MeCab 解析器插件。本节描述了解析行为的差异。全文搜索相关的配置选项也适用。
有关 MeCab 解析器的更多信息,请参考 Github 上的MeCab: Yet Another Part-of-Speech and Morphological Analyzer项目。
安装 MeCab 解析器插件
MeCab 解析器插件需要mecab和mecab-ipadic。
在支持的 Fedora、Debian 和 Ubuntu 平台上(除了 Ubuntu 12.04,系统中的mecab版本太旧),如果mecab安装在默认位置,则 MySQL 会动态链接到系统的mecab安装。在其他支持的类 Unix 平台上,libmecab.so静态链接在libpluginmecab.so中,该文件位于 MySQL 插件目录中。mecab-ipadic包含在 MySQL 二进制文件中,位于*MYSQL_HOME*\\lib\\mecab中。
你可以使用本机包管理工具(在 Fedora、Debian 和 Ubuntu 上)安装mecab和mecab-ipadic,也可以从源代码构建mecab和mecab-ipadic。有关使用本机包管理工具安装mecab和mecab-ipadic的信息,请参见从二进制发行版安装 MeCab(可选)。如果你想从源代码构建mecab和mecab-ipadic,请参见从源代码构建 MeCab(可选)。
在 Windows 上,libmecab.dll位于 MySQL 的bin目录中。mecab-ipadic位于*MYSQL_HOME*/lib/mecab中。
要安装和配置 MeCab 解析器插件,请执行以下步骤:
在 MySQL 配置文件中,将mecab_rc_file配置选项设置为mecabrc配置文件的位置,该文件是 MeCab 的配置文件。如果你使用 MySQL 分发的 MeCab 包,mecabrc 文件位于MYSQL_HOME/lib/mecab/etc/。
[mysqld]
loose-mecab-rc-file=MYSQL_HOME/lib/mecab/etc/mecabrc
loose前缀是一个选项修饰符。在安装 MeCab 解析器插件之前,MySQL 不会识别mecab_rc_file选项,但必须在尝试安装 MeCab 解析器插件之前设置它。loose前缀允许你重新启动 MySQL,而不会因为无法识别的变量而遇到错误。
如果你使用自己的 MeCab 安装,或者从源代码构建 MeCab,mecabrc配置文件的位置可能会有所不同。
有关 MySQL 配置文件及其位置的信息,请参见 Section 6.2.2.2,“使用选项文件”。
同样在 MySQL 配置文件中,将最小标记大小设置为 1 或 2,这是与 MeCab 解析器一起使用时推荐的值。对于InnoDB表,最小标记大小由innodb_ft_min_token_size配置选项定义,默认值为 3。对于MyISAM表,最小标记大小由ft_min_word_len定义,默认值为 4。
[mysqld]
innodb_ft_min_token_size=1
修改mecabrc配置文件以指定你想使用的字典。MySQL 二进制文件中分发的mecab-ipadic包含三个字典(ipadic_euc-jp、ipadic_sjis和ipadic_utf-8)。MySQL 打包的mecabrc配置文件包含类似以下条目:
dicdir = /path/to/mysql/lib/mecab/lib/mecab/dic/ipadic_euc-jp
要使用ipadic_utf-8字典,例如,修改条目如下:
dicdir=*MYSQL_HOME*/lib/mecab/dic/ipadic_utf-8
如果您正在使用自己的 MeCab 安装或已经从源代码构建了 MeCab,那么mecabrc文件中的默认dicdir条目可能会有所不同,字典及其位置也会不同。
注意
安装完 MeCab 解析器插件后,您可以使用mecab_charset状态变量查看与 MeCab 一起使用的字符集。MySQL 二进制文件提供的三个 MeCab 字典支持以下字符集。
ipadic_euc-jp字典支持ujis和eucjpms字符集。
ipadic_sjis字典支持sjis和cp932字符集。
ipadic_utf-8字典支持utf8mb3和utf8mb4字符集。
mecab_charset仅报告第一个支持的字符集。例如,ipadic_utf-8字典支持utf8mb3和utf8mb4。当使用此字典时,mecab_charset总是报告utf8。
重新启动 MySQL。
安装 MeCab 解析器插件:
使用INSTALL PLUGIN安装 MeCab 解析器插件。插件名称为mecab,共享库名称为libpluginmecab.so。有关安装插件的其他信息,请参见 Section 7.6.1, “Installing and Uninstalling Plugins”。
INSTALL PLUGIN mecab SONAME \’libpluginmecab.so\’;
安装完成后,MeCab 解析器插件会在每次正常 MySQL 重启时加载。
使用SHOW PLUGINS语句验证 MeCab 解析器插件是否已加载。
mysql> SHOW PLUGINS;
mecab插件应该出现在插件列表中。
创建使用 MeCab 解析器的 FULLTEXT 索引
要创建一个使用 mecab 解析器的FULLTEXT索引,请在CREATE TABLE、ALTER TABLE或CREATE INDEX中指定WITH PARSER ngram。
此示例演示了创建带有mecab FULLTEXT索引的表,插入示例数据,并在 Information Schema INNODB_FT_INDEX_CACHE表中查看标记化数据:
mysql> USE test;
mysql> CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT (title,body) WITH PARSER mecab
) ENGINE=InnoDB CHARACTER SET utf8mb4;
mysql> SET NAMES utf8mb4;
mysql> INSERT INTO articles (title,body) VALUES
(\’データベース管理\’,\’このチュートリアルでは、私はどのようにデータベースを管理する方法を紹介します\’),
(\’データベースアプリケーション開発\’,\’データベースアプリケーションを開発することを学ぶ\’);
mysql> SET GLOBAL innodb_ft_aux_table=\”test/articles\”;
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE ORDER BY doc_id, position;
要向现有表添加FULLTEXT索引,可以使用ALTER TABLE或CREATE INDEX。例如:
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT
) ENGINE=InnoDB CHARACTER SET utf8mb4;
ALTER TABLE articles ADD FULLTEXT INDEX ft_index (title,body) WITH PARSER mecab;
# Or:
CREATE FULLTEXT INDEX ft_index ON articles (title,body) WITH PARSER mecab;
MeCab 解析器空格处理
MeCab 解析器在查询字符串中使用空格作为分隔符。例如,MeCab 解析器将データベース管理标记为データベース和管理。
MeCab 解析器停用词处理
默认情况下,MeCab 解析器使用默认的停用词列表,其中包含一小部分英文停用词。要使用适用于日语的停用词列表,您必须创建自己的停用词列表。有关创建停用词列表的信息,请参见 第 14.9.4 节,“全文停用词”。
MeCab 解析器术语搜索
对于自然语言模式搜索,搜索词被转换为标记的并集。例如,データベース管理 被转换为 データベース 管理。
SELECT COUNT(*) FROM articles WHERE MATCH(title,body) AGAINST(\’データベース管理\’ IN NATURAL LANGUAGE MODE);
对于布尔模式搜索,搜索词被转换为搜索短语。例如,データベース管理 被转换为 データベース 管理。
SELECT COUNT(*) FROM articles WHERE MATCH(title,body) AGAINST(\’データベース管理\’ IN BOOLEAN MODE);
MeCab 解析器通配符搜索
通配符搜索词不被标记。对前缀 データベース管理* 进行搜索时,会在前缀 データベース管理 上执行搜索。
SELECT COUNT(*) FROM articles WHERE MATCH(title,body) AGAINST(\’データベース*\’ IN BOOLEAN MODE);
MeCab 解析器短语搜索
短语被标记。例如,データベース管理 被标记为 データベース 管理。
SELECT COUNT(*) FROM articles WHERE MATCH(title,body) AGAINST(\’\”データベース管理\”\’ IN BOOLEAN MODE);
从二进制发行版安装 MeCab(可选)
本节描述了如何使用本机软件包管理工具从二进制发行版安装 mecab 和 mecab-ipadic。例如,在 Fedora 上,您可以使用 Yum 执行安装:
yum mecab-devel
在 Debian 或 Ubuntu 上,您可以执行 APT 安装:
apt-get install mecab
apt-get install mecab-ipadic
从源代码安装 MeCab(可选)
如果您想要从源代码构建 mecab 和 mecab-ipadic,以下是基本的安装步骤。有关更多信息,请参考 MeCab 文档。
从 taku910.github.io/mecab/#download 下载 mecab 和 mecab-ipadic 的 tar.gz 软件包。截至 2016 年 2 月,最新可用的软件包是 mecab-0.996.tar.gz 和 mecab-ipadic-2.7.0-20070801.tar.gz。
安装 mecab:
tar zxfv mecab-0.996.tar
cd mecab-0.996
./configure
make
make check
su
make install
安装 mecab-ipadic:
tar zxfv mecab-ipadic-2.7.0-20070801.tar
cd mecab-ipadic-2.7.0-20070801
./configure
make
su
make install
使用 WITH_MECAB CMake 选项编译 MySQL。如果您已将 mecab 和 mecab-ipadic 安装到默认位置,请将 WITH_MECAB 选项设置为 system。
-DWITH_MECAB=system
如果您定义了自定义安装目录,请将 WITH_MECAB 设置为自定义目录。例如:
-DWITH_MECAB=/path/to/mecab
14.10 转换函数和运算符
原文:dev.mysql.com/doc/refman/8.0/en/cast-functions.html
表 14.15 转换函数和运算符
名称描述已弃用BINARY将字符串转换为二进制字符串8.0.27CAST()将值转换为特定类型CONVERT()将值转换为特定类型
转换函数和运算符使值从一种数据类型转换为另一种数据类型。
转换函数和运算符描述
字符集转换
用于字符串比较的字符集转换
空间类型的转换操作
转换操作的其他用途
转换函数和运算符描述
BINARY expr
BINARY 运算符将表达式转换为二进制字符串(具有 binary 字符集和 binary 校对的字符串)。BINARY 的常见用途是通过使用数值字节值而不是逐个字符来进行字符字符串比较。BINARY 运算符还导致比较中的尾随空格具有重要意义。有关 binary 字符集和非二进制字符集的 _bin 校对之间的区别的信息,请参见 第 12.8.5 节,“二进制校对与 _bin 校对的比较”。
BINARY 运算符在 MySQL 8.0.27 中已弃用,并且您应该期望在将来的 MySQL 版本中将其移除。请改用 CAST(… AS BINARY)。
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
-> OK
mysql> SELECT \’a\’ = \’A\’;
-> 1
mysql> SELECT BINARY \’a\’ = \’A\’;
-> 0
mysql> SELECT \’a\’ = \’a \’;
-> 1
mysql> SELECT BINARY \’a\’ = \’a \’;
-> 0
在比较中,BINARY 影响整个操作;可以在任一操作数之前使用,结果相同。
要将字符串表达式转换为二进制字符串,以下结构是等效的:
CONVERT(*expr* USING BINARY)
CAST(*expr* AS BINARY)
BINARY *expr*
如果一个值是字符串文字,可以通过使用 _binary 字符集引导符将其指定为二进制字符串而无需转换:
mysql> SELECT \’a\’ = \’A\’;
-> 1
mysql> SELECT _binary \’a\’ = \’A\’;
-> 0
有关引导符的信息,请参见 第 12.3.8 节,“字符集引导符”。
在表达式中,BINARY 运算符的效果与字符列定义中的 BINARY 属性不同。对于使用 BINARY 属性定义的字符列,MySQL 分配表默认字符集和该字符集的二进制 (_bin) 校对。每个非二进制字符集都有一个 _bin 校对。例如,如果表默认字符集是 utf8mb4,那么这两个列定义是等效的:
CHAR(10) BINARY
CHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
在 CHAR、VARCHAR 或 TEXT 列的定义中使用 CHARACTER SET binary 会导致该列被视为相应的二进制字符串数据类型。例如,以下定义对是等效的:
CHAR(10) CHARACTER SET binary
BINARY(10)
VARCHAR(10) CHARACTER SET binary
VARBINARY(10)
TEXT CHARACTER SET binary
BLOB
如果从 mysql 客户端调用 BINARY,二进制字符串将使用十六进制表示,具体取决于 –binary-as-hex 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”。
CAST(*expr* AS *type* [ARRAY])
CAST(*timestamp_value* AT TIME ZONE *timezone_specifier* AS DATETIME[(*precision*)])
timezone_specifier: [INTERVAL] ‘+00:00’ | ‘UTC’
使用 CAST(*expr* AS *type* 语法,CAST() 函数接受任何类型的表达式,并生成指定类型的结果值。这个操作也可以表示为 CONVERT(*expr*, *type*),它是等效的。如果 expr 是 NULL,CAST() 返回 NULL。
允许使用以下 type 值:
BINARY[(*N*)]
生成一个具有 VARBINARY 数据类型的字符串,除非表达式 expr 为空(长度为零),结果类型为 BINARY(0)。如果给定可选长度 N,BINARY(*N*) 使转换不超过 N 个字节的参数。长度小于 N 的值用 0x00 字节填充到长度为 N。如果未给出可选长度 N,MySQL 从表达式计算最大长度。如果提供或计算的长度大于内部阈值,则结果类型为 BLOB。如果长度仍然太长,则结果类型为 LONGBLOB。
有关将 BINARY 转换影响比较的描述,请参阅 Section 13.3.3, “The BINARY and VARBINARY Types”。
CHAR[(*N*)] [*charset_info*]
生成一个具有VARCHAR数据类型的字符串,除非表达式 expr 为空(长度为零),在这种情况下,结果类型为 CHAR(0)。如果给定了可选长度 N,CHAR(*N*) 使转换不超过 N 个字符的参数。对于长度小于 N 的值,不会进行填充。如果未给出可选长度 N,MySQL 会从表达式计算最大长度。如果提供或计算的长度大于内部阈值,则结果类型为 TEXT。如果长度仍然太长,则结果类型为 LONGTEXT。
没有 charset_info 子句时,CHAR 生成一个具有默认字符集的字符串。要明确指定字符集,允许使用以下 charset_info 值:
CHARACTER SET *charset_name*:生成具有给定字符集的字符串。
ASCII:CHARACTER SET latin1 的简写。
UNICODE:CHARACTER SET ucs2 的简写。
在所有情况下,字符串具有字符集默认排序规则。
日期
生成一个日期值。
DATETIME[(*M*)]
生成一个日期时间值。如果给定了可选 M 值,则指定了小数秒精度。
DECIMAL[(*M*[,*D*])]
生成一个DECIMAL值。如果给定了可选的 M 和 D 值,则它们指定了数字的最大位数(精度)和小数点后的位数(标度)。如果省略了 D,则假定为 0。如果省略了 M,则假定为 10。
DOUBLE
生成一个DOUBLE结果。在 MySQL 8.0.17 中添加。
FLOAT[(*p*)]
如果未指定精度 p,则生成一个FLOAT类型的结果。如果提供了 p 并且 0 <= < p <= 24,则结果为 FLOAT 类型。如果 25 <= p <= 53,则结果为DOUBLE类型。如果 p < 0 或 p > 53,则返回错误。在 MySQL 8.0.17 中添加。
JSON
生成一个JSON值。有关值在JSON和其他类型之间转换规则的详细信息,请参阅 JSON 值的比较和排序。
NCHAR[(*N*)]
类似于 CHAR,但生成具有国家字符集的字符串。请参阅第 12.3.7 节,“国家字符集”。
与 CHAR 不同,NCHAR 不允许指定尾随字符集信息。
REAL
产生一个REAL类型的结果。如果启用了REAL_AS_FLOAT SQL 模式,则实际上是FLOAT;否则结果为DOUBLE类型。
SIGNED [INTEGER]
产生一个带符号的BIGINT值。
spatial_type
截至 MySQL 8.0.24 版本,CAST() 和 CONVERT() 支持将几何值从一种空间类型转换为另一种空间类型,适用于某些空间类型的组合。有关详细信息,请参见空间类型的转换操作。
TIME[(*M*)]
产生一个TIME值。如果给定了可选的*M*值,则指定小数秒精度。
UNSIGNED [INTEGER]
产生一个无符号的BIGINT值。
YEAR
产生一个YEAR值。在 MySQL 8.0.22 版本中添加。这些规则适用于转换为YEAR:
对于范围在 1901-2155(包括)之间的四位数,或者可以解释为此范围内四位数的字符串,返回相应的YEAR值。
对于由一到两位数字组成的数字,或者可以解释为这样一个数字的字符串,返回如下YEAR值:
如果数字在 1-69(包括)范围内,则加上 2000 并返回总和。
如果数字在 70-99(包括)范围内,则加上 1900 并返回总和。
对于评估为 0 的字符串,返回 2000。
对于数字 0,返回 0。
对于DATE、DATETIME或TIMESTAMP值,返回值的YEAR部分。对于TIME值,返回当前年份。
如果不指定TIME参数的类型,则可能会得到与预期不同的结果,如下所示:
mysql> SELECT CAST(\”11:35:00\” AS YEAR), CAST(TIME \”11:35:00\” AS YEAR);
+————————–+——————————-+
| CAST(\”11:35:00\” AS YEAR) | CAST(TIME \”11:35:00\” AS YEAR) |
+————————–+——————————-+
| 2011 | 2021 |
+————————–+——————————-+
如果参数是DECIMAL、DOUBLE、DECIMAL或REAL类型,则将值四舍五入到最接近的整数,然后尝试使用整数值的规则将值转换为YEAR,如下所示:
mysql> SELECT CAST(1944.35 AS YEAR), CAST(1944.50 AS YEAR);
+———————–+———————–+
| CAST(1944.35 AS YEAR) | CAST(1944.50 AS YEAR) |
+———————–+———————–+
| 1944 | 1945 |
+———————–+———————–+
mysql> SELECT CAST(66.35 AS YEAR), CAST(66.50 AS YEAR);
+———————+———————+
| CAST(66.35 AS YEAR) | CAST(66.50 AS YEAR) |
+———————+———————+
| 2066 | 2067 |
+———————+———————+
不能将类型为GEOMETRY的参数转换为YEAR。
对于无法成功转换为YEAR的值,返回NULL。
包含必须在转换之前截断的非数字字符的字符串值会引发警告,如下所示:
mysql> SELECT CAST(\”1979aaa\” AS YEAR);
+————————-+
| CAST(\”1979aaa\” AS YEAR) |
+————————-+
| 1979 |
+————————-+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+———+——+——————————————-+
| Level | Code | Message |
+———+——+——————————————-+
| Warning | 1292 | Truncated incorrect YEAR value: \’1979aaa\’ |
+———+——+——————————————-+
在 MySQL 8.0.17 及更高版本中,InnoDB允许在CREATE INDEX、CREATE TABLE和ALTER TABLE语句中使用额外的ARRAY关键字来创建 JSON 数组的多值索引。除了在这些语句中用于创建多值索引时,不支持ARRAY。被索引的列必须是 JSON 类型的列。使用ARRAY时,AS关键字后面的*type*可以指定CAST()支持的任何类型,但不包括BINARY、JSON和YEAR。有关语法信息和示例,以及其他相关信息,请参见多值索引。
注意
与CAST()不同,CONVERT() 不支持多值索引创建或ARRAY关键字。
从 MySQL 8.0.22 开始,CAST()支持使用AT TIMEZONE运算符将TIMESTAMP值检索为 UTC 时间。唯一支持的时区是 UTC;可以将其指定为\’+00:00\’或\’UTC\’。此语法支持的唯一返回类型是DATETIME,其精度范围为 0 到 6,包括 0 和 6。
使用时区偏移的TIMESTAMP值也受支持。
mysql> SELECT @@system_time_zone;
+——————–+
| @@system_time_zone |
+——————–+
| EDT |
+——————–+
1 row in set (0.00 sec)
mysql> CREATE TABLE TZ (c TIMESTAMP);
Query OK, 0 rows affected (0.41 sec)
mysql> INSERT INTO tz VALUES
-> ROW(CURRENT_TIMESTAMP),
-> ROW(\’2020-07-28 14:50:15+1:00\’);
Query OK, 1 row affected (0.08 sec)
mysql> TABLE tz;
+———————+
| c |
+———————+
| 2020-07-28 09:22:41 |
| 2020-07-28 09:50:15 |
+———————+
2 rows in set (0.00 sec)
mysql> SELECT CAST(c AT TIME ZONE \’+00:00\’ AS DATETIME) AS u FROM tz;
+———————+
| u |
+———————+
| 2020-07-28 13:22:41 |
| 2020-07-28 13:50:15 |
+———————+
2 rows in set (0.00 sec)
mysql> SELECT CAST(c AT TIME ZONE \’UTC\’ AS DATETIME(2)) AS u FROM tz;
+————————+
| u |
+————————+
| 2020-07-28 13:22:41.00 |
| 2020-07-28 13:50:15.00 |
+————————+
2 rows in set (0.00 sec)
如果您在CAST()的这种形式中使用\’UTC\’作为时区指定符,并且服务器引发错误,例如未知或不正确的时区:‘UTC’,则可能需要安装 MySQL 时区表(请参阅填充时区表)。
AT TIME ZONE不支持ARRAY关键字,并且不受CONVERT()函数支持。
CONVERT(*expr* USING *transcoding_name*)
CONVERT(*expr*,*type*)
CONVERT(*expr* USING *transcoding_name*)是标准的 SQL 语法。CONVERT()的非USING形式是 ODBC 语法。无论使用哪种语法,如果*expr*为NULL,该函数都会返回NULL。
CONVERT(*expr* USING *transcoding_name*)在不同字符集之间转换数据。在 MySQL 中,转码名称与相应的字符集名称相同。例如,此语句将默认字符集中的字符串\’abc\’转换为utf8mb4字符集中的相应字符串:
SELECT CONVERT(\’abc\’ USING utf8mb4);
CONVERT(*expr*, *type*)语法(不带USING)接受一个表达式和一个*type*值,指定结果类型,并产生指定类型的结果值。此操作也可以表示为CAST(*expr* AS *type*),这是等效的。有关更多信息,请参阅CAST()的描述。
注意
在 MySQL 8.0.28 之前,这个函数有时允许将BINARY值无效地转换为非二进制字符集。当CONVERT()作为索引生成列表达式的一部分时,这可能导致在从先前版本的 MySQL 升级后出现索引损坏。有关如何处理这种情况的信息,请参见 SQL 更改。
字符集转换
带有USING子句的CONVERT()在字符集之间转换数据:
CONVERT(*expr* USING *transcoding_name*)
在 MySQL 中,转码名称与相应的字符集名称相同。
例子:
SELECT CONVERT(\’test\’ USING utf8mb4);
SELECT CONVERT(_latin1\’Müller\’ USING utf8mb4);
INSERT INTO utf8mb4_table (utf8mb4_column)
SELECT CONVERT(latin1_column USING utf8mb4) FROM latin1_table;
要在字符集之间转换字符串,还可以使用CONVERT(*expr*, *type*)语法(不带USING),或者等效的CAST(*expr* AS *type*):
CONVERT(*string*, CHAR[(*N*)] CHARACTER SET *charset_name*)
CAST(*string* AS CHAR[(*N*)] CHARACTER SET *charset_name*)
例子:
SELECT CONVERT(\’test\’, CHAR CHARACTER SET utf8mb4);
SELECT CAST(\’test\’ AS CHAR CHARACTER SET utf8mb4);
如果你像刚才展示的那样指定CHARACTER SET *charset_name*,结果的字符集和排序规则分别为*charset_name和charset_name*的默认排序规则。如果省略CHARACTER SET *charset_name*,结果的字符集和排序规则由确定默认连接字符集和排序规则的character_set_connection和collation_connection系统变量定义(参见第 12.4 节,“连接字符集和排序规则”)。
在CONVERT()或CAST()调用中不允许使用COLLATE子句,但可以将其应用于函数结果。例如,以下是合法的:
SELECT CONVERT(\’test\’ USING utf8mb4) COLLATE utf8mb4_bin;
SELECT CONVERT(\’test\’, CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin;
SELECT CAST(\’test\’ AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin;
但以下是不合法的:
SELECT CONVERT(\’test\’ USING utf8mb4 COLLATE utf8mb4_bin);
SELECT CONVERT(\’test\’, CHAR CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);
SELECT CAST(\’test\’ AS CHAR CHARACTER SET utf8mb4 COLLATE utf8mb4_bin);
对于字符串字面值,指定字符集的另一种方法是使用字符集引导符。在前面的示例中,_latin1和_latin2是引导符的实例。与转换函数(如CAST()或CONVERT())不同,这些函数将字符串从一个字符集转换为另一个字符集,引导符指定字符串字面值具有特定的字符集,不涉及转换。有关更多信息,请参见第 12.3.8 节,“字符集引导符”。
字符串比较的字符集转换
通常情况下,你无法以不区分大小写的方式比较BLOB值或其他二进制字符串,因为二进制字符串使用binary字符集,该字符集没有与大小写概念相关的排序规则。要执行不区分大小写的比较,首先使用CONVERT()或CAST()函数将值转换为非二进制字符串。对转换后的字符串进行比较时使用其排序规则。例如,如果转换结果的排序规则不区分大小写,则LIKE操作也不区分大小写。这对于以下操作是正确的,因为默认的utf8mb4排序规则(utf8mb4_0900_ai_ci)不区分大小写:
SELECT \’A\’ LIKE CONVERT(*blob_col* USING utf8mb4)
FROM *tbl_name*;
要为转换后的字符串指定特定的排序规则,请在CONVERT()调用后使用COLLATE子句:
SELECT \’A\’ LIKE CONVERT(*blob_col* USING utf8mb4) COLLATE utf8mb4_unicode_ci
FROM *tbl_name*;
要使用不同的字符集,请在前述语句中用其名称替换utf8mb4(类似地,要使用不同的排序规则也是如此)。
CONVERT()和CAST()可以更普遍地用于比较以不同字符集表示的字符串。例如,对这些字符串进行比较会导致错误,因为它们具有不同的字符集:
mysql> SET @s1 = _latin1 \’abc\’, @s2 = _latin2 \’abc\’;
mysql> SELECT @s1 = @s2;
ERROR 1267 (HY000): Illegal mix of collations (latin1_swedish_ci,IMPLICIT)
and (latin2_general_ci,IMPLICIT) for operation \’=\’
将其中一个字符串转换为与另一个兼容的字符集,使比较可以顺利进行:
mysql> SELECT @s1 = CONVERT(@s2 USING latin1);
+———————————+
| @s1 = CONVERT(@s2 USING latin1) |
+———————————+
| 1 |
+———————————+
字符集转换在对二进制字符串进行大小写转换之前也很有用。当直接应用于二进制字符串时,LOWER()和UPPER()是无效的,因为大小写概念不适用。要对二进制字符串执行大小写转换,首先使用适合字符串中存储的数据的字符集将其转换为非二进制字符串:
mysql> SET @str = BINARY \’New York\’;
mysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING utf8mb4));
+————-+————————————+
| LOWER(@str) | LOWER(CONVERT(@str USING utf8mb4)) |
+————-+————————————+
| New York | new york |
+————-+————————————+
请注意,如果将BINARY、CAST()或CONVERT()应用于索引列,MySQL 可能无法有效地使用索引。
对空间类型执行转换操作
从 MySQL 8.0.24 开始,CAST()和CONVERT()支持将几何值从一种空间类型转换为另一种空间类型,适用于某些空间类型的组合。以下列表显示了允许的类型组合,其中“MySQL 扩展”指的是 MySQL 中实现的超出 SQL/MM 标准定义的转换:
从Point到:
MultiPoint
GeometryCollection
从LineString到:
Polygon(MySQL 扩展)
MultiPoint(MySQL 扩展)
MultiLineString
GeometryCollection
从Polygon到:
LineString(MySQL 扩展)
MultiLineString(MySQL 扩展)
MultiPolygon
GeometryCollection
从MultiPoint到:
Point
LineString(MySQL 扩展)
GeometryCollection
从MultiLineString到:
LineString
Polygon(MySQL 扩展)
MultiPolygon(MySQL 扩展)
GeometryCollection
从MultiPolygon到:
Polygon
MultiLineString(MySQL 扩展)
GeometryCollection
从GeometryCollection到:
Point
LineString
Polygon
MultiPoint
MultiLineString
MultiPolygon
在空间转换中,GeometryCollection和GeomCollection是相同结果类型的同义词。
一些条件适用于所有空间类型转换,而一些条件仅适用于转换结果为特定空间类型时。有关“格式良好的几何”等术语的信息,请参阅第 13.4.4 节,“几何格式良好性和有效性”。
空间转换的一般条件
转换为 Point 的条件
转换为 LineString 的条件
转换为 Polygon 的条件
转换为 MultiPoint 的条件
转换为 MultiLineString 的条件
转换为 MultiPolygon 的条件
转换为 GeometryCollection 的条件
空间转换的一般条件
这些条件适用于所有空间转换,无论结果类型如何:
转换的结果与要转换的表达式的 SRS 相同。
在空间类型之间进行转换不会改变坐标值或顺序。
如果要转换的表达式为NULL,函数结果为NULL。
不允许使用带有指定空间类型的RETURNING子句的JSON_VALUE()函数来转换空间类型。
不允许将空间类型转换为ARRAY。
如果空间类型组合是允许的,但要转换的表达式不是一个语法上良好形成的几何图形,将会发生一个ER_GIS_INVALID_DATA错误。
如果空间类型组合是允许的,但要转换的表达式是在未定义的空间参考系统(SRS)中语法上良好形成的几何图形,则会发生一个ER_SRS_NOT_FOUND错误。
如果要转换的表达式具有地理 SRS 但经度或纬度超出范围,则会发生错误:
如果经度值不在范围(−180, 180]内,则会发生一个ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE错误。
如果纬度值不在范围[−90, 90]内,则会发生一个ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE错误。
显示的范围以度为单位。如果 SRS 使用另一个单位,则范围使用其单位中的相应值。由于浮点运算,确切的范围限制略有偏差。
转换为点的条件
当转换结果类型为Point时,应用以下条件:
如果要转换的表达式是一个Point类型的良好形成的几何图形,则函数结果为该Point。
如果要转换的表达式是一个只包含单个Point的MultiPoint类型的良好形成的几何图形,则函数结果为该Point。如果表达式包含多个Point,则会发生一个ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是一个只包含单个Point的GeometryCollection类型的良好形成的几何图形,则函数结果为该Point。如果表达式为空,包含多个Point或包含其他几何类型,则会发生一个ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是除Point、MultiPoint、GeometryCollection之外的其他类型的良好形成的几何图形,则会发生一个ER_INVALID_CAST_TO_GEOMETRY错误。
转换为 LineString 的条件
当转换结果类型为LineString时,应用以下条件:
如果要转换的表达式是一个LineString类型的良好形成的几何图形,则函数结果为该LineString。
如果要转换的表达式是类型为Polygon且没有内环的形状,则函数结果是一个LineString,其中包含外环的点按相同顺序排列。如果表达式有内环,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是包含至少两个点的类型为MultiPoint的形状,则函数结果是一个LineString,其中包含MultiPoint中点的顺序与表达式中出现的顺序相同。如果表达式只包含一个Point,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是包含单个LineString的类型为MultiLineString的形状,则函数结果是该LineString。如果表达式包含多个LineString,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是包含单个LineString的类型为GeometryCollection的形状,则函数结果是该LineString。如果表达式为空,包含多个LineString或包含其他几何类型,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是除LineString、Polygon、MultiPoint、MultiLineString或GeometryCollection之外类型的形状,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。
转换为多边形的条件
当转换结果类型为Polygon时,应满足以下条件:
如果要转换的表达式是类型为LineString的形状,且是一个环(即起点和终点相同),则函数结果是一个外环由LineString中的点按相同顺序组成的Polygon。如果表达式不是环,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。如果环的顺序不正确(外环必须是逆时针方向),则会出现ER_INVALID_CAST_POLYGON_RING_DIRECTION错误。
如果要转换的表达式是类型为Polygon的形状,则函数结果是该Polygon。
如果要转换的表达式是类型为MultiLineString且所有元素都是环的形状良好的几何图形,则函数结果是以第一个LineString作为外环,任何额外的LineString值作为内环的Polygon。如果表达式的任何元素不是环,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。如果任何环不按正确顺序排列(外环必须是逆时针,内环必须是顺时针),则会发生ER_INVALID_CAST_POLYGON_RING_DIRECTION错误。
如果要转换的表达式是类型为MultiPolygon且包含单个Polygon的形状良好的几何图形,则函数结果是该Polygon。如果表达式包含多个Polygon,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是类型为GeometryCollection且仅包含单个Polygon的形状良好的几何图形,则函数结果是该Polygon。如果表达式为空,包含多个Polygon或包含其他几何类型,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是类型为LineString、Polygon、MultiLineString、MultiPolygon或GeometryCollection之外的形状良好的几何图形,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
转换为 MultiPoint 的条件
当转换结果类型为MultiPoint时,应满足以下条件:
如果要转换的表达式是类型为Point的形状良好的几何图形,则函数结果是包含该Point作为唯一元素的MultiPoint。
如果要转换的表达式是类型为LineString的形状良好的几何图形,则函数结果是按相同顺序包含LineString的点的MultiPoint。
如果要转换的表达式是类型为MultiPoint的形状良好的几何图形,则函数结果是该MultiPoint。
如果要转换的表达式是类型为GeometryCollection且仅包含点的形状良好的几何图形,则函数结果是包含这些点的MultiPoint。如果GeometryCollection为空或包含其他几何类型,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是类型为Point、LineString、MultiPoint或GeometryCollection之外的形状良好的几何图形,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
转换为 MultiLineString 的条件
当转换结果类型为MultiLineString时,应满足以下条件:
如果要转换的表达式是类型为LineString的格式良好的几何图形,则函数结果为包含该LineString作为唯一元素的MultiLineString。
如果要转换的表达式是类型为Polygon的格式良好的几何图形,则函数结果为包含Polygon的外环作为第一个元素,任何内环作为额外元素按表达式中出现顺序排列的MultiLineString。
如果要转换的表达式是类型为MultiLineString的格式良好的几何图形,则函数结果为该MultiLineString。
如果要转换的表达式是仅包含没有内环的多边形的MultiPolygon的格式良好的几何图形,则函数结果为包含多边形环按表达式中出现顺序排列的MultiLineString。如果表达式包含任何带有内环的多边形,则会发生ER_WRONG_PARAMETERS_TO_STORED_FCT错误。
如果要转换的表达式是仅包含线串的GeometryCollection的格式良好的几何图形,则函数结果为包含这些线串的MultiLineString。如果表达式为空或包含其他几何类型,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是类型为LineString、Polygon、MultiLineString、MultiPolygon或GeometryCollection之外的格式良好的几何图形,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。
转换为 MultiPolygon 的条件
当转换结果类型为MultiPolygon时,应满足以下条件:
如果要转换的表达式是类型为Polygon的格式良好的几何图形,则函数结果为包含该Polygon作为唯一元素的MultiPolygon。
如果要转换的表达式是所有元素均为环的类型为MultiLineString的格式良好的几何图形,则函数结果为包含每个元素的仅具有外环的Polygon的MultiPolygon。如果任何元素不是环,则会发生ER_INVALID_CAST_TO_GEOMETRY错误。如果任何环不按正确顺序(外环必须逆时针)排列,则会发生ER_INVALID_CAST_POLYGON_RING_DIRECTION错误。
如果要转换的表达式是类型为MultiPolygon的格式良好的几何图形,则函数结果为该MultiPolygon。
如果要转换的表达式是一个只包含多边形的GeometryCollection类型的形状,函数的结果是包含这些多边形的MultiPolygon。如果表达式为空或包含其他几何类型,则会出现ER_INVALID_CAST_TO_GEOMETRY错误。
如果要转换的表达式是除了Polygon、MultiLineString、MultiPolygon或GeometryCollection之外的其他类型的形状,会出现ER_INVALID_CAST_TO_GEOMETRY错误。
转换为 GeometryCollection 的条件
当转换结果类型为GeometryCollection时,这些条件适用:
GeometryCollection和GeomCollection是相同结果类型的同义词。
如果要转换的表达式是一个只包含点的Point类型的形状,函数的结果是包含该点作为唯一元素的GeometryCollection。
如果要转换的表达式是一个只包含线串的LineString类型的形状,函数的结果是包含该线串作为唯一元素的GeometryCollection。
如果要转换的表达式是一个只包含多边形的Polygon类型的形状,函数的结果是包含该多边形作为唯一元素的GeometryCollection。
如果要转换的表达式是一个只包含多点的MultiPoint类型的形状,函数的结果是按照表达式中出现的顺序包含这些点的GeometryCollection。
如果要转换的表达式是一个只包含多线串的MultiLineString类型的形状,函数的结果是按照表达式中出现的顺序包含这些线串的GeometryCollection。
如果要转换的表达式是一个只包含多边形的MultiPolygon类型的形状,函数的结果是按照表达式中出现的顺序包含MultiPolygon的元素的GeometryCollection。
如果要转换的表达式是一个只包含 GeometryCollection 的GeometryCollection类型的形状,函数的结果就是那个GeometryCollection。
转换操作的其他用途
转换函数在CREATE TABLE … SELECT语句中创建具有特定类型的列时非常有用:
mysql> CREATE TABLE new_table SELECT CAST(\’2000-01-01\’ AS DATE) AS c1;
mysql> SHOW CREATE TABLE new_table\\G
*************************** 1\\. row ***************************
Table: new_table
Create Table: CREATE TABLE `new_table` (
`c1` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
转换函数对于按字典顺序排序ENUM列非常有用。通常,对ENUM列的排序使用内部数值。将值转换为CHAR会导致字典排序:
SELECT *enum_col* FROM *tbl_name* ORDER BY CAST(*enum_col* AS CHAR);
CAST()也会改变结果,如果你将其作为更复杂表达式的一部分,比如CONCAT(\’Date: \’,CAST(NOW() AS DATE))。
对于时间值,很少需要使用CAST()以不同格式提取数据。而是使用诸如EXTRACT()、DATE_FORMAT()或TIME_FORMAT()等函数。请参阅第 14.7 节,“日期和时间函数”。
要将字符串转换为数字,通常只需在数字上下文中使用字符串值:
mysql> SELECT 1+\’1\’;
-> 2
十六进制和位字面值也是默认的二进制字符串。
mysql> SELECT X\’41\’, X\’41\’+0;
-> \’A\’, 65
mysql> SELECT b\’1100001\’, b\’1100001\’+0;
-> \’a\’, 97
在算术运算中使用的字符串在表达式评估期间被转换为浮点数。
在字符串上下文中使用的数字被转换为字符串:
mysql> SELECT CONCAT(\’hello you \’,2);
-> \’hello you 2\’
有关将数字隐式转换为字符串的信息,请参阅第 14.3 节,“表达式评估中的类型转换”。
MySQL 支持带符号和无符号 64 位值的算术运算。对于数值运算符(如+或-),其中一个操作数是无符号整数时,默认结果是无符号的(参见第 14.6.1 节,“算术运算符”)。要覆盖此行为,使用SIGNED或UNSIGNED强制转换运算符将值分别转换为有符号或无符号 64 位整数。
mysql> SELECT 1 – 2;
-> -1
mysql> SELECT CAST(1 – 2 AS UNSIGNED);
-> 18446744073709551615
mysql> SELECT CAST(CAST(1 – 2 AS UNSIGNED) AS SIGNED);
-> -1
如果任一操作数是浮点值,则结果是浮点值,并且不受前述规则的影响。(在此上下文中,DECIMAL列值被视为浮点值。)
mysql> SELECT CAST(1 AS UNSIGNED) – 2.0;
-> -1.0
SQL 模式会影响转换操作的结果(请参阅第 7.1.11 节,“服务器 SQL 模式”)。示例:
对于将“零”日期字符串转换为日期,当启用NO_ZERO_DATE SQL 模式时,CONVERT()和CAST()返回NULL并产生警告。
对于整数减法,如果启用了NO_UNSIGNED_SUBTRACTION SQL 模式,则减法结果是有符号的,即使任何操作数都是无符号的。
14.11 XML 函数
原文:dev.mysql.com/doc/refman/8.0/en/xml-functions.html
表 14.16 XML 函数
名称描述ExtractValue()使用 XPath 表示法从 XML 字符串中提取值UpdateXML()返回替换的 XML 片段
本节讨论了 MySQL 中的 XML 及相关功能。
注意
可以通过在 –xml 选项下调用 mysql 和 mysqldump 客户端来从 MySQL 中获取 XML 格式化输出。请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”,以及 Section 6.5.4, “mysqldump — A Database Backup Program”。
提供基本 XPath 1.0(XML Path Language,版本 1.0)功能的两个函数可用。关于 XPath 语法和用法的一些基本信息稍后在本节中提供;但是,关于这些主题的深入讨论超出了本手册的范围,您应参考 XML Path Language (XPath) 1.0 标准 获取确切信息。对于对 XPath 新手或希望复习基础知识的人来说,Zvon.org XPath 教程 是一个有用的资源,提供多种语言版本。
注意
这些函数仍在开发中。我们将继续改进 MySQL 8.0 及以后版本中的 XML 和 XPath 功能的其他方面。您可以在 MySQL XML 用户论坛 中讨论这些问题,提出问题,并从其他用户那里获得帮助。
与这些函数一起使用的 XPath 表达式支持用户变量和存储程序局部变量。用户变量进行弱类型检查;存储程序局部变量进行强类型检查(另请参见 Bug #26518):
用户变量(弱类型检查)。 使用 $@*variable_name*(即用户变量)语法的变量不受检查。如果变量类型错误或之前未分配值,服务器不会发出警告或错误。这也意味着用户完全负责任何打字错误,因为如果(例如)使用 $@myvairable 而意图使用 $@myvariable,服务器不会发出警告。
示例:
mysql> SET @xml = \'<a><b>X</b><b>Y</b></a>\’;
Query OK, 0 rows affected (0.00 sec)
mysql> SET @i =1, @j = 2;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @i, ExtractValue(@xml, \’//b[$@i]\’);
+——+——————————–+
| @i | ExtractValue(@xml, \’//b[$@i]\’) |
+——+——————————–+
| 1 | X |
+——+——————————–+
1 row in set (0.00 sec)
mysql> SELECT @j, ExtractValue(@xml, \’//b[$@j]\’);
+——+——————————–+
| @j | ExtractValue(@xml, \’//b[$@j]\’) |
+——+——————————–+
| 2 | Y |
+——+——————————–+
1 row in set (0.00 sec)
mysql> SELECT @k, ExtractValue(@xml, \’//b[$@k]\’);
+——+——————————–+
| @k | ExtractValue(@xml, \’//b[$@k]\’) |
+——+——————————–+
| NULL | |
+——+——————————–+
1 row in set (0.00 sec)
存储程序中的变量(强类型检查)。 使用 $*variable_name* 语法声明和使用这些函数时,当它们在存储程序内部调用时,这些变量是局部于定义它们的存储程序,并且对类型和值进行了强类型检查。
示例:
mysql> DELIMITER |
mysql> CREATE PROCEDURE myproc ()
-> BEGIN
-> DECLARE i INT DEFAULT 1;
-> DECLARE xml VARCHAR(25) DEFAULT \'<a>X</a><a>Y</a><a>Z</a>\’;
->
-> WHILE i < 4 DO
-> SELECT xml, i, ExtractValue(xml, \’//a[$i]\’);
-> SET i = i+1;
-> END WHILE;
-> END |
Query OK, 0 rows affected (0.01 sec)
mysql> DELIMITER ;
mysql> CALL myproc();
+————————–+—+——————————+
| xml | i | ExtractValue(xml, \’//a[$i]\’) |
+————————–+—+——————————+
| <a>X</a><a>Y</a><a>Z</a> | 1 | X |
+————————–+—+——————————+
1 row in set (0.00 sec)
+————————–+—+——————————+
| xml | i | ExtractValue(xml, \’//a[$i]\’) |
+————————–+—+——————————+
| <a>X</a><a>Y</a><a>Z</a> | 2 | Y |
+————————–+—+——————————+
1 row in set (0.01 sec)
+————————–+—+——————————+
| xml | i | ExtractValue(xml, \’//a[$i]\’) |
+————————–+—+——————————+
| <a>X</a><a>Y</a><a>Z</a> | 3 | Z |
+————————–+—+——————————+
1 row in set (0.01 sec)
参数。 在存储过程内部 XPath 表达式中使用的变量作为参数传递时也要进行严格检查。
包含用户变量或存储程序本地变量的表达式必须(除了符号)符合 XPath 1.0 规范中包含变量的 XPath 表达式的规则。
注意
用于存储 XPath 表达式的用户变量被视为空字符串。因此,不可能将 XPath 表达式存储为用户变量。(Bug #32911)
ExtractValue(*xml_frag*, *xpath_expr*)
ExtractValue()接受两个字符串参数,一个是 XML 标记片段*xml_frag,另一个是 XPath 表达式xpath_expr*(也称为定位器);它返回与 XPath 表达式匹配的元素的第一个文本节点的文本(CDATA)。
使用此函数等同于在追加/text()后使用*xpath_expr进行匹配。换句话说,ExtractValue(\'<a><b>Sakila</b></a>\’, \’/a/b\’)和ExtractValue(\'<a><b>Sakila</b></a>\’, \’/a/b/text()\’)产生相同的结果。如果xml_frag或xpath_expr*为NULL,函数将返回NULL。
如果找到多个匹配项,则返回每个匹配元素的第一个子文本节点的内容(按匹配顺序)作为一个单独的、以空格分隔的字符串。
如果找不到与表达式匹配的文本节点(包括隐式的/text())——无论出于何种原因,只要*xpath_expr有效,xml_frag*由正确嵌套和关闭的元素组成——则返回空字符串。不区分匹配空元素和根本没有匹配。这是设计上的考虑。
如果您需要确定*xml_frag*中是否找不到匹配元素或找到这样的元素但不包含子文本节点,您应该测试使用 XPath count()函数的表达式的结果。例如,这两个语句都返回空字符串,如下所示:
mysql> SELECT ExtractValue(\'<a><b/></a>\’, \’/a/b\’);
+————————————-+
| ExtractValue(\'<a><b/></a>\’, \’/a/b\’) |
+————————————-+
| |
+————————————-+
1 row in set (0.00 sec)
mysql> SELECT ExtractValue(\'<a><c/></a>\’, \’/a/b\’);
+————————————-+
| ExtractValue(\'<a><c/></a>\’, \’/a/b\’) |
+————————————-+
| |
+————————————-+
1 row in set (0.00 sec)
然而,您可以通过以下方式确定是否实际上存在匹配的元素:
mysql> SELECT ExtractValue(\'<a><b/></a>\’, \’count(/a/b)\’);
+————————————-+
| ExtractValue(\'<a><b/></a>\’, \’count(/a/b)\’) |
+————————————-+
| 1 |
+————————————-+
1 row in set (0.00 sec)
mysql> SELECT ExtractValue(\'<a><c/></a>\’, \’count(/a/b)\’);
+————————————-+
| ExtractValue(\'<a><c/></a>\’, \’count(/a/b)\’) |
+————————————-+
| 0 |
+————————————-+
1 row in set (0.01 sec)
重要提示
ExtractValue()仅返回CDATA,不返回匹配标记内可能包含的任何标记,也不返回它们的内容(请参见以下示例中作为val1返回的结果)。
mysql> SELECT
-> ExtractValue(\'<a>ccc<b>ddd</b></a>\’, \’/a\’) AS val1,
-> ExtractValue(\'<a>ccc<b>ddd</b></a>\’, \’/a/b\’) AS val2,
-> ExtractValue(\'<a>ccc<b>ddd</b></a>\’, \’//b\’) AS val3,
-> ExtractValue(\'<a>ccc<b>ddd</b></a>\’, \’/b\’) AS val4,
-> ExtractValue(\'<a>ccc<b>ddd</b><b>eee</b></a>\’, \’//b\’) AS val5;
+——+——+——+——+———+
| val1 | val2 | val3 | val4 | val5 |
+——+——+——+——+———+
| ccc | ddd | ddd | | ddd eee |
+——+——+——+——+———+
此函数使用当前的 SQL 校对规则来与contains()进行比较,执行与其他字符串函数(如CONCAT())相同的校对聚合,考虑到它们的参数的校对可强制性;请参阅第 12.8.4 节,“表达式中的校对可强制性”,了解规定此行为的规则的解释。
(以前,总是使用二进制—即,区分大小写—比较。)
如果*xml_frag*包含未正确嵌套或关闭的元素,则返回NULL,并生成警告,如下例所示:
mysql> SELECT ExtractValue(\'<a>c</a><b\’, \’//a\’);
+———————————–+
| ExtractValue(\'<a>c</a><b\’, \’//a\’) |
+———————————–+
| NULL |
+———————————–+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\\G
*************************** 1\\. row ***************************
Level: Warning
Code: 1525
Message: Incorrect XML value: \’parse error at line 1 pos 11:
END-OF-INPUT unexpected (\’>\’ wanted)\’ 1 row in set (0.00 sec)
mysql> SELECT ExtractValue(\'<a>c</a><b/>\’, \’//a\’);
+————————————-+
| ExtractValue(\'<a>c</a><b/>\’, \’//a\’) |
+————————————-+
| c |
+————————————-+
1 row in set (0.00 sec)
UpdateXML(*xml_target*, *xpath_expr*, *new_xml*)
此函数用新的 XML 片段*new_xml替换给定 XML 标记片段xml_target的单个部分,然后返回更改后的 XML。被替换的xml_target部分与用户提供的 XPath 表达式xpath_expr*匹配。
如果找不到与*xpath_expr匹配的表达式,或者找到多个匹配项,则该函数返回原始的xml_target* XML 片段。所有三个参数都应为字符串。如果UpdateXML()的任何参数为NULL,则函数返回NULL。
mysql> SELECT
-> UpdateXML(\'<a><b>ccc</b><d></d></a>\’, \’/a\’, \'<e>fff</e>\’) AS val1,
-> UpdateXML(\'<a><b>ccc</b><d></d></a>\’, \’/b\’, \'<e>fff</e>\’) AS val2,
-> UpdateXML(\'<a><b>ccc</b><d></d></a>\’, \’//b\’, \'<e>fff</e>\’) AS val3,
-> UpdateXML(\'<a><b>ccc</b><d></d></a>\’, \’/a/d\’, \'<e>fff</e>\’) AS val4,
-> UpdateXML(\'<a><d></d><b>ccc</b><d></d></a>\’, \’/a/d\’, \'<e>fff</e>\’) AS val5
-> \\G
*************************** 1\\. row ***************************
val1: <e>fff</e>
val2: <a><b>ccc</b><d></d></a>
val3: <a><e>fff</e><d></d></a>
val4: <a><b>ccc</b><e>fff</e></a>
val5: <a><d></d><b>ccc</b><d></d></a>
注意
对 XPath 语法和用法的深入讨论超出了本手册的范围。请参阅XML Path Language (XPath) 1.0 规范以获取确切信息。对于那些对 XPath 新手或希望在基础知识方面进行复习的人来说,Zvon.org XPath 教程是一个有用的资源,提供多种语言版本。
以下是一些基本 XPath 表达式的描述和示例:
/*tag*
仅当<*tag*/>是根元素时,才匹配<*tag*/>。
示例:/a在<a><b/></a>中有匹配项,因为它匹配最外层(根)标记。它不匹配<b><a/></b>中的内部*a*元素,因为在这种情况下,它是另一个元素的子元素。
/*tag1*/*tag2*
仅当<*tag2*/>是<*tag1*/>的子元素,并且<*tag1*/>是根元素时,才匹配<*tag2*/>。
示例:/a/b匹配 XML 片段<a><b/></a>中的*b元素,因为它是根元素a的子元素。它在<b><a/></b>中没有匹配项,因为在这种情况下,b是根元素(因此不是其他元素的子元素)。XPath 表达式在<a><c><b/></c></a>中也没有匹配项;这里,b是a的后代,但实际上不是a*的子元素。
此结构可扩展到三个或更多元素。例如,XPath 表达式/a/b/c匹配片段<a><b><c/></b></a>中的*c*元素。
//*tag*
匹配任何<*tag*>的实例。
示例://a 匹配以下任意一个元素中的*a*元素:<a><b><c/></b></a>;<c><a><b/></a></b>;<c><b><a/></b></c>。
//可以与/结合使用。例如,//a/b匹配片段<a><b/></a>或<c><a><b/></a></c>中的b元素。
注意
//*tag*等同于/descendant-or-self::*/*tag*。一个常见错误是将其与/descendant-or-self::*tag*混淆,尽管后者的表达实际上可能导致非常不同的结果,如下所示:
mysql> SET @xml = \'<a><b><c>w</c><b>x</b><d>y</d>z</b></a>\’;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @xml;
+—————————————–+
| @xml |
+—————————————–+
| <a><b><c>w</c><b>x</b><d>y</d>z</b></a> |
+—————————————–+
1 row in set (0.00 sec)
mysql> SELECT ExtractValue(@xml, \’//b[1]\’);
+——————————+
| ExtractValue(@xml, \’//b[1]\’) |
+——————————+
| x z |
+——————————+
1 row in set (0.00 sec)
mysql> SELECT ExtractValue(@xml, \’//b[2]\’);
+——————————+
| ExtractValue(@xml, \’//b[2]\’) |
+——————————+
| |
+——————————+
1 row in set (0.01 sec)
mysql> SELECT ExtractValue(@xml, \’/descendant-or-self::*/b[1]\’);
+—————————————————+
| ExtractValue(@xml, \’/descendant-or-self::*/b[1]\’) |
+—————————————————+
| x z |
+—————————————————+
1 row in set (0.06 sec)
mysql> SELECT ExtractValue(@xml, \’/descendant-or-self::*/b[2]\’);
+—————————————————+
| ExtractValue(@xml, \’/descendant-or-self::*/b[2]\’) |
+—————————————————+
| |
+—————————————————+
1 row in set (0.00 sec)
mysql> SELECT ExtractValue(@xml, \’/descendant-or-self::b[1]\’);
+————————————————-+
| ExtractValue(@xml, \’/descendant-or-self::b[1]\’) |
+————————————————-+
| z |
+————————————————-+
1 row in set (0.00 sec)
mysql> SELECT ExtractValue(@xml, \’/descendant-or-self::b[2]\’);
+————————————————-+
| ExtractValue(@xml, \’/descendant-or-self::b[2]\’) |
+————————————————-+
| x |
+————————————————-+
1 row in set (0.00 sec)
*运算符充当“通配符”,匹配任何元素。例如,表达式/*/b匹配 XML 片段<a><b/></a>或<c><b/></c>中的b元素。然而,在片段<b><a/></b>中,该表达式不会产生匹配,因为b必须是其他元素的子元素。通配符可以在任何位置使用:表达式/*/b/*匹配b元素的任何子元素,该子元素本身不是根元素。
您可以使用|(UNION)运算符匹配多个定位器中的任何一个。例如,表达式//b|//c匹配 XML 目标中的所有b和c元素。
还可以根据一个或多个属性的值匹配元素。使用语法*tag*[@*attribute*=\”*value*\”]。例如,表达式//b[@id=\”idB\”]匹配片段<a><b id=\”idA\”/><c/><b id=\”idB\”/></a>中的第二个b元素。要匹配具有*attribute*=\”*value*\”的任何元素,请使用 XPath 表达式//*[*attribute*=\”*value*\”]。
要过滤多个属性值,只需连续使用多个属性比较子句。例如,表达式//b[@c=\”x\”][@d=\”y\”]匹配出现在给定 XML 片段中的任何位置的元素<b c=\”x\” d=\”y\”/>。
要查找具有多个值中的任何一个匹配的元素,可以使用由|运算符连接的多个定位器。例如,要匹配所有b元素,其c属性具有值 23 或 17 中的任何一个,请使用表达式//b[@c=\”23\”]|//b[@c=\”17\”]。您也可以使用逻辑or运算符来实现此目的://b[@c=\”23\” or @c=\”17\”]。
注意
or和|之间的区别在于or连接条件,而|连接结果集。
XPath 限制。 这些函数支持的 XPath 语法目前受到以下限制:
不支持节点集到节点集的比较(例如\’/a/b[@c=@d]\’)。
所有标准的 XPath 比较运算符都受支持。(Bug #22823)
相对定位器表达式在根节点的上下文中解析。例如,考虑以下查询和结果:
mysql> SELECT ExtractValue(
-> \'<a><b c=\”1\”>X</b><b c=\”2\”>Y</b></a>\’,
-> \’a/b\’
-> ) AS result;
+——–+
| result |
+——–+
| X Y |
+——–+
1 row in set (0.03 sec)
在这种情况下,定位器a/b解析为/a/b。
在谓词内也支持相对定位器。在以下示例中,d[../@c=\”1\”]解析为/a/b[@c=\”1\”]/d:
mysql> SELECT ExtractValue(
-> \'<a>
-> <b c=\”1\”><d>X</d></b>
-> <b c=\”2\”><d>X</d></b>
-> </a>\’,
-> \’a/b/d[../@c=\”1\”]\’)
-> AS result;
+——–+
| result |
+——–+
| X |
+——–+
1 row in set (0.00 sec)
不允许使用作为标量值评估的表达式前缀定位器,包括变量引用、文字、数字和标量函数调用,其使用会导致错误。
:: 运算符与以下节点类型的组合不受支持:
*axis*::comment()
*axis*::text()
*axis*::processing-instructions()
*axis*::node()
然而,名称测试(如*axis*::*name*和*axis*::*)是受支持的,如下例所示:
mysql> SELECT ExtractValue(\'<a><b>x</b><c>y</c></a>\’,\’/a/child::b\’);
+——————————————————-+
| ExtractValue(\'<a><b>x</b><c>y</c></a>\’,\’/a/child::b\’) |
+——————————————————-+
| x |
+——————————————————-+
1 row in set (0.02 sec)
mysql> SELECT ExtractValue(\'<a><b>x</b><c>y</c></a>\’,\’/a/child::*\’);
+——————————————————-+
| ExtractValue(\'<a><b>x</b><c>y</c></a>\’,\’/a/child::*\’) |
+——————————————————-+
| x y |
+——————————————————-+
1 row in set (0.01 sec)
在路径会导致“超出”根元素的情况下,不支持“上下”导航。也就是说,您不能使用在给定元素的祖先的后代上匹配的表达式,其中当前元素的一个或多个祖先也是根元素的祖先(请参见 Bug #16321)。
不支持以下 XPath 函数,或者存在已知问题,如下所示:
id()
lang()
local-name()
name()
namespace-uri()
normalize-space()
starts-with()
string()
substring-after()
substring-before()
translate()
不支持以下轴:
following-sibling
following
preceding-sibling
preceding
作为参数传递给 ExtractValue() 和 UpdateXML() 的 XPath 表达式可能包含元素选择器中的冒号字符(:),这使它们可以与使用 XML 命名空间表示法的标记一起使用。例如:
mysql> SET @xml = \'<a>111<b:c>222<d>333</d><e:f>444</e:f></b:c></a>\’;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT ExtractValue(@xml, \’//e:f\’);
+—————————–+
| ExtractValue(@xml, \’//e:f\’) |
+—————————–+
| 444 |
+—————————–+
1 row in set (0.00 sec)
mysql> SELECT UpdateXML(@xml, \’//b:c\’, \'<g:h>555</g:h>\’);
+——————————————–+
| UpdateXML(@xml, \’//b:c\’, \'<g:h>555</g:h>\’) |
+——————————————–+
| <a>111<g:h>555</g:h></a> |
+——————————————–+
1 row in set (0.00 sec)
这在某些方面类似于 Apache Xalan 和其他一些解析器允许的内容,比起要求命名空间声明或使用 namespace-uri() 和 local-name() 函数要简单得多。
错误处理。 对于 ExtractValue() 和 UpdateXML(),使用的 XPath 定位器必须有效,并且要搜索的 XML 必须由正确嵌套和关闭的元素组成。如果定位器无效,则会生成错误:
mysql> SELECT ExtractValue(\'<a>c</a><b/>\’, \’/&a\’);
ERROR 1105 (HY000): XPATH syntax error: \’&a\’
如果 xml_frag 不包含正确嵌套和关闭的元素,则返回 NULL 并生成警告,如下例所示:
mysql> SELECT ExtractValue(\'<a>c</a><b\’, \’//a\’);
+———————————–+
| ExtractValue(\'<a>c</a><b\’, \’//a\’) |
+———————————–+
| NULL |
+———————————–+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\\G
*************************** 1\\. row ***************************
Level: Warning
Code: 1525
Message: Incorrect XML value: \’parse error at line 1 pos 11:
END-OF-INPUT unexpected (\’>\’ wanted)\’ 1 row in set (0.00 sec)
mysql> SELECT ExtractValue(\'<a>c</a><b/>\’, \’//a\’);
+————————————-+
| ExtractValue(\'<a>c</a><b/>\’, \’//a\’) |
+————————————-+
| c |
+————————————-+
1 row in set (0.00 sec)
重要提示
作为传递给 UpdateXML() 的第三个参数的替换 XML 不会 被检查,以确定它是否仅由正确嵌套和关闭的元素组成。
XPath 注入。 代码注入发生在恶意代码被引入系统以获取未经授权的权限和数据时。它基于开发人员对用户输入数据类型和内容所做的假设。XPath 也不例外。
一个常见的情况是应用程序处理授权的情况,通过将登录名和密码的组合与 XML 文件中找到的内容进行匹配,使用类似于以下的 XPath 表达式:
//user[login/text()=\’neapolitan\’ and password/text()=\’1c3cr34m\’]/attribute::id
这是类似于 SQL 语句的 XPath 等效语句:
SELECT id FROM users WHERE login=\’neapolitan\’ AND password=\’1c3cr34m\’;
使用 XPath 的 PHP 应用程序可能会处理登录过程如下:
<?php
$file = \”users.xml\”;
$login = $POST[\”login\”];
$password = $POST[\”password\”];
$xpath = \”//user[login/text()=$login and password/text()=$password]/attribute::id\”;
if( file_exists($file) )
{
$xml = simplexml_load_file($file);
if($result = $xml->xpath($xpath))
echo \”You are now logged in as user $result[0].\”;
else
echo \”Invalid login name or password.\”;
}
else
exit(\”Failed to open $file.\”);
?>
输入上没有进行检查。这意味着恶意用户可以通过在登录名和密码中输入\’ or 1=1来“绕过”测试,导致$xpath被评估如下所示:
//user[login/text()=\’\’ or 1=1 and password/text()=\’\’ or 1=1]/attribute::id
由于方括号内的表达式始终评估为true,它实际上与这个表达式相同,该表达式匹配 XML 文档中每个user元素的id属性:
//user/attribute::id
可以简单地通过在$xpath的定义中引用要插入的变量名来规避这种特定攻击,强制从 Web 表单传递的值转换为字符串:
$xpath = \”//user[login/text()=\’$login\’ and password/text()=\’$password\’]/attribute::id\”;
这与通常用于防止 SQL 注入攻击的策略相同。一般来说,用于防止 XPath 注入攻击的实践应该与防止 SQL 注入攻击的实践相同:
永远不要在应用程序中接受未经测试的用户数据。
检查所有用户提交的数据的类型;拒绝或转换错误类型的数据。
测试数值数据是否超出范围;截断、四舍五入或拒绝超出范围的值。测试字符串是否包含非法字符,要么将其剥离,要么拒绝包含这些字符的输入。
不要输出可能向未经授权的用户提供线索以危害系统的明确错误消息;而是将这些记录到文件或数据库表中。
就像 SQL 注入攻击可以用于获取有关数据库模式的信息一样,XPath 注入也可以用于遍历 XML 文件以揭示其结构,如 Amit Klein 的论文Blind XPath Injection(PDF 文件,46KB)中所讨论的。
重要的是检查发送回客户端的输出。考虑当我们使用 MySQL ExtractValue() 函数时可能发生的情况:
mysql> SELECT ExtractValue(
-> LOAD_FILE(\’users.xml\’),
-> \’//user[login/text()=\”\” or 1=1 and password/text()=\”\” or 1=1]/attribute::id\’
-> ) AS id;
+——————————-+
| id |
+——————————-+
| 00327 13579 02403 42354 28570 |
+——————————-+
1 row in set (0.01 sec)
因为 ExtractValue() 将多个匹配项作为一个以空格分隔的字符串返回,这种注入攻击将 users.xml 中的每个有效 ID 作为单行输出提供给用户。作为额外的保障,你还应该在返回给用户之前测试输出。这里是一个简单的例子:
mysql> SELECT @id = ExtractValue(
-> LOAD_FILE(\’users.xml\’),
-> \’//user[login/text()=\”\” or 1=1 and password/text()=\”\” or 1=1]/attribute::id\’
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT IF(
-> INSTR(@id, \’ \’) = 0,
-> @id,
-> \’Unable to retrieve user ID\’)
-> AS singleID;
+—————————-+
| singleID |
+—————————-+
| Unable to retrieve user ID |
+—————————-+
1 row in set (0.00 sec)
一般来说,将数据安全返回给用户的指导原则与接受用户输入的原则相同。这可以总结为:
始终测试传出数据的类型和允许的值。
永远不要允许未经授权的用户查看可能提供有关应用程序信息的错误消息,这些信息可能被用于利用它。
#以上关于MySQL8 中文参考(四十九)的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92448.html