我正在将在LATIN1中创建的MySQL数据库迁移到UTF8。为此,我首先将每一列更改为相应的二进制类型,然后更改为UTF8:
ALTER TABLE clientes CHARACTER SET utf8;
ALTER TABLE clientes change nombre nombre varbinary(255);
ALTER TABLE clientes change nombre nombre varchar(255) character set utf8;
因为,根据所有文档,这是防止数据损坏的正确方法...
...但是,数据仍然被破坏。我只举两个例子:
这些数据是如何输入的?嗯,数据库是PHP Web应用程序的后端,该数据库使用UTF8进行所有操作(包括使用“ SET NAMES UTF8” 连接到MySQL服务器)...除了正确创建数据库外。因此,我假设添加的所有数据都在UTF8中。
总结:看来我在LATIN1列中存储了UTF8文本,现在我尝试将列更改为UTF8,文本被截断了。
为什么会这样?我该怎么办?
编辑:忘记了,由于我没有命令行访问权限,因此我正在通过PhpMyAdmin执行所有操作。
答案 0 :(得分:1)
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
表是字符集latin1,并在latin1中正确编码;想 utf8mb4:
ALTER TABLE tbl CONVERT TO CHARACTER SET utf8mb4;
我不知道您的数据是否无法挽回。请提供其中一行以及十六进制。
十六进制
“Larrasoaña”编码为4C61727261736F61 F1 61,“JesúsyMaría”编码为4A6573 FA 732079204D6172 ED 6120
那些是latin1编码的(或latin5或dec8)。如果表定义(SHOW CREATE TABLE
)为latin1,则您可以保留它。 (latin1
处理西欧语言,但不处理亚洲语言。)
如果要将所有文本列都转换为utf8或utf8mb4,请像我上面介绍的那样执行ALTER
。您的3-Alter方法将不能正常运行;假设latin1列中的字节实际上是UTF-8字节(不是)。
但是...您必须根据客户端的需求指定客户端的编码。客户端和表是否一致并不重要,因为将提供转换。
为什么三步更改失败
ALTER TABLE clientes CHARACTER SET utf8;
-设置 new 列的默认字符集。它不会影响现有的列定义以及这些列中的任何数据。
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字节,则该过程是适当的。也就是说,如果它已经是C3B1
的2字节ñ
。 (顺便说一句,这通常表现为“ 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。
如果它给您留下了乱七八糟的列,特别是如果行被截断了,那么您需要返回到备份,或者以其他方式重新加载数据。