使用破折号的MySQL字符串匹配

时间:2020-09-14 17:39:02

标签: mysql

我目前正在将数据从Windows上的MySQL 5.6.41迁移到Windows上的MySQL 8.0.21。总体而言,迁移过程非常顺利,但遇到了一些令人沮丧的问题。有一张看起来像这样的桌子:

CREATE TABLE `domains` (
`intDomainID` int(11) NOT NULL AUTO_INCREMENT,
`txtDomain` varchar(100) NOT NULL,
`dtDateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`blnTor` int(1) NOT NULL DEFAULT '0',
`txtTLD` varchar(100) NOT NULL,
PRIMARY KEY (`intDomainID`),
UNIQUE KEY `txtDomain` (`txtDomain`)
ENGINE=InnoDB AUTO_INCREMENT=10127897 DEFAULT CHARSET=utf8mb4;

CREATE SCHEMA已经完成,并且是由Workbench的“复制到剪贴板”->“创建模式”功能创建的。

当我使用内置的Workbench导出/导入时,导入总是失败,并显示“ txtDomain中的值重复”错误(此处解释),这很奇怪,因为原始表对该字段具有UNIQUE KEY约束,因此不能是重复项,我确认,它作为重复项找到的值不是原始数据库中的重复项。

然后我使用SELECT ... INTO OUTFILE转储表,将文件移到新服务器上,然后执行LOAD DATE INFILE。这也因相同的“ txtDomain中的值重复”错误而失败。

然后我删除了UNIQUE KEY约束,并重命名了LOAD DATE INFILE。这样就可以了,数据在那里。但是,由于“重复”,我无法添加回UNIQUE KEY约束。我调查后发现:

在MySQL 5.6.41上的查询结果: Query result on MySQL 5.6.41

在MySQL 8.0.21上的查询结果: Query result on MySQL 8.0.21

现在,这是怎么回事?表定义,数据库,表和字段字符集/排序规则是相同的。我需要UNIQUE KEY约束...

为什么http://d­­eepdot35wv­­m­eyd5.onion:80 == http://d­­ee-p---dot35w-v­­m­eyd5.onion:80 ??

如果有帮助,我的导出命令:

SELECT * INTO OUTFILE 'S:\\temp\\domains.txt'
  FIELDS TERMINATED BY ',' 
  OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\r\n'
  FROM domains;

我的导入命令:

LOAD DATA INFILE 'E:\\DB Backup\\ServerMigration\\domains.txt' 
INTO TABLE domains
  FIELDS TERMINATED BY ',' 
  OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\r\n';

集合: 排序规则旧服务器:utf8_general_ci [我不记得触摸此值了] 新服务器:utf8mb4_0900_ai_ci [我没有碰到这个值] 新旧数据库相同:utf8mb4_0900_ai_ci 新旧表相同:utf8mb4_0900_ai_ci

这是原始TXT文件在文件系统上的样子: Some "bad" values in the exported file

请注意,如果我将屏幕快照中的一个URL粘贴到此处,它将神奇地变成“正确”的值,没有破折号: 即:http://deepdot35w­­v­­­m­­­eyd5.onion:80

注2:使用Notepad ++,如果我将常规的“破折号”转换为十六进制,则会得到“ 2D”。但是,如果我从引起麻烦的URL中转换一个,则会得到HEX“ C2AD”。看来我正在处理一个奇怪的unicode字符而不是一个破折号?

注3:如果有人想要一个小的示例文件,则为: https://www.dropbox.com/s/1ssbl95t2jgn2xy/domains_small.zip

1 个答案:

答案 0 :(得分:2)

有问题的字符是U + 00AD“ SOFT HYPHEN”-一种不可打印的字符,用于表示单词中可能的连字符点。

在新设置(使用默认排序规则设置的MySQL 8.0)上,使用COLLATION处理这些字符的方式似乎与在旧设置(使用默认排序规则设置的MySQL 5.7)上对字符的处理方式不同:

在比较中,现在这些<不可打印的字符被忽略

您可以使用此简单的小提琴来测试差异。在5.6中比较为“ 0”,而在MySQL 8.0-> https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=a9bd0bf7de815dc14a886c5069bd1a0f

中为“ 1”

请注意,SQL小提琴未明确指定时,也会使用默认排序规则配置。

您可以通过为txtDomain列设置二进制UTF-8排序规则来解决此问题,无论如何,这实际上是您想要的技术字符串:

CREATE TABLE `domains` (
  `intDomainID` int(11) NOT NULL AUTO_INCREMENT,
  `txtDomain` varchar(100) NOT NULL 
      CHARACTER SET utf8mb4
      COLLATE utf8mb4_binary_ci,
  `dtDateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `blnTor` int(1) NOT NULL DEFAULT '0',
  `txtTLD` varchar(100) NOT NULL,
  PRIMARY KEY (`intDomainID`),
  UNIQUE KEY `txtDomain` (`txtDomain`)
) ENGINE=InnoDB AUTO_INCREMENT=10127897 DEFAULT CHARSET=utf8mb4;

更新:事实证明,旧版本(5.6)和新版本(8.0)的COLLATION必须有所不同,因为utf8mb4_0900_ai_ci是MySQL 8.0引入的。旧排序规则必须是utf8mb4_general_ci,在应用时也显示了MySQL 8.0中的所需行为。

但是,无论如何,您仍然应该对技术字符串(例如URL)使用二进制排序规则。