F1 和 FA 是 latin1 编码。你需要告诉 MySQL 数据是latin1。一种方法是通过SET NAMES latin1。
但请注意...这与您尝试将数据存储到的列的设置独立。而且,现在,utf8mb4 是文本的首选设置。 MySQL 将在列的编码和客户端的编码之间进行转换。但是你必须通过连接参数(或SET NAMES)告诉它客户端的编码。
ALTER TABLEs 对适用于某些情况,而不是所有情况!您可能想要http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases 中的第一个条目
表是 CHARACTER SET latin1 并在 latin1 中正确编码;想
utf8mb4:
ALTER TABLE tbl CONVERT TO CHARACTER SET utf8mb4;
我不知道您的数据是否已被不可挽回地占用。请提供其中一行以及 HEX。
十六进制
“Larrasoaña”编码为 4C61727261736F61F161,“Jesús y María”编码为 4A6573FA732079204D6172ED6120
这些是 latin1 编码的(或 latin5 或 dec8)。如果表定义 (SHOW CREATE TABLE) 显示 latin1,那么您可以不理会它。 (latin1 处理西欧语言,但不处理亚洲语言。)
如果要将所有文本列转换为 utf8 或 utf8mb4,请像我上面介绍的那样执行 ALTER。您的 3-Alter 方法将不正常工作;它假定 latin1 列中的字节实际上是 UTF-8 字节(它们不是)。
但是...您必须根据客户的需要指定客户的编码。 客户端和桌子是否同意并不重要,因为将提供转换。
为什么 3 步改变失败
ALTER TABLE clientes CHARACTER SET utf8; -- 这会为 new 列设置 default 字符集。它对现有的列定义和这些列中的任何数据没有影响。
ALTER TABLE clientes change nombre nombre varbinary(255); -- 这表示“忘记任何文本编码”。那就是 F1 现在只是一堆位,而不是 ñ 的 latin1 表示。
ALTER TABLE clientes change nombre nombre varchar(255) character set utf8; -- 这需要那些 varbinary 位并说“让我们将它们视为utf8。这会给出错误消息,因为 F1 不是 utf8 的有效编码。
该过程是合适的如果字节是已经 utf8字节。也就是说,如果它已经是 ñ 的 2 字节 C3B1。 (顺便说一下,这通常表现为“Mojibake”,当解释为 latin1 时显示为 ñ。)
1-Alter 过程...
ALTER TABLE clientes CONVERT TO CHARACTER SET utf8;(转换整个表)或ALTER TABLE clientes MODIFY nombre varchar(255) character set utf8;(仅转换一列)。他们做以下事情:
对于每个文本(char/varchar/text)列,它根据其当前编码(latin1,F1)读取数据,将其转换为 utf8(或 utf8mb4)(C3B1)并写回该行。同时将声明改为CHARACTER SET utf8。
也就是说,在不更改“文本”的情况下更改CHARACTER SET 是“正确的”过程。确实,编码发生了变化(F1 -> C3B1),但这与CHARACTER SET的变化一致。
恢复
您的前 2 个 ALTER 有效,对吗?第三个是成功了、失败了还是留下了一张乱七八糟的桌子?
如果它中止了,留下varbinary,然后再做2个改变:首先回到latin1;然后直接转utf8。
如果它给你留下了一个混乱的列,特别是如果行被截断,那么你需要返回备份,或者重新加载数据。