如何清理 MySQL 中带有特殊字符的数据

How to clean data with special characters in MySQL

一个干净的数据怎么能像这样 Réationl’Oreal 分别在 MySQL 中看起来像这样 R'actionL'Oreal

这看起来像是 "double encoding" 的一个例子。这是右手在说 utf8,而左手在听 latin1 的地方。参见 and See also http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases

Réation -> Réation 取消双重编码后

但你说 R'action -- 我想知道你输入的 ée' 还是 'e? 我还假设你的意思是 L’Oreal? (注意 'right single quote mark' 而不是 'apostrophe'。)

首先,我们需要验证它是否真的是一个普通的双重编码。

SELECT col, HEX(col) FROM ... WHERE ...

应该给你这个 Réation 的十六进制:

52  E9       6174696F6E  -- latin1 encoding
52 C3A9      6174696F6E  -- utf8 encoding
52 C383 C2A9 6174696F6E  -- double encoding

(忽略间距。)

如果你得到了其中的第三个,请继续我的答案。 如果你得到任何其他东西,停止! -- 问题比我想象的要复杂

现在,看看双重编码修复是否会修复它(修复之前):

SELECT col, CONVERT(BINARY(CONVERT(CONVERT(
                  BINARY(CONVERT(col USING latin1)) USING utf8mb4)
                      USING latin1)) USING utf8mb4)
     FROM tbl;

你需要防止它发生修复数据。 以下部分是不可逆的;在 table!

的副本上测试它

您的案例是:CHARACTER SET latin1,但其中有 utf8/utf8mb4 个字节;修复字符集时保留字节:

首先,假设您有 tbl.col 的声明:

col VARCHAR(111) CHARACTER SET latin1 NOT NULL

然后在不更改字节的情况下转换列:

ALTER TABLE tbl MODIFY COLUMN col VARBINARY(111) NOT NULL;
ALTER TABLE tbl MODIFY COLUMN col VARCHAR(111) CHARACTER SET utf8mb4 NOT NULL;

注意:如果您以 TEXT 开头,请使用 BLOB 作为中间定义。 (一定要保持其他规格相同 - VARCHARNOT NULL 等)

对每个 table 中有问题的每一列都这样做。

(在本次讨论中,我不区分 utf8mb4 和 utf8。大多数文本都非常满意;Emoji 和一些中文需要 utf8mb4,而不仅仅是 utf8。)

来自评论

        CONVERT(UNHEX('C38EC2B2') USING utf8mb4) = 'β'  (Greek beta)
CONVERT(CONVERT(UNHEX('C38EC2B2') USING latin1) USING utf8mb4) = 'β'

我的结论:首先你有一些配置错误。然后您应用了一项或多项 错误的 修复。你现在乱七八糟,我不敢帮你解开。也就是说,混乱不仅仅是 "double encoding".

如果可能,重新开始,确保在添加更多数据之前正确存储了一些测试数据。如果数据不好,不要尝试修复数据;退后并重新开始。请参阅 "Trouble..." 中的 "best bractice" 以正确设置。我会在附近帮助您解释您在 table 中看到的十六进制是否正确。