使用非utf8编码的MySQL SUBSTRING()

时间:2018-12-11 10:01:00

标签: mysql encoding

我有一个使用latin1编码的MySQL数据库,并且我在为函数SUBSTRING()苦苦挣扎,该函数显然是在计算字节数而不是字符,如以下情况所示:

MySQL [hozana]> set names utf8;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SELECT SUBSTRING('ééééé', 1, 3);
+-------------------------------+
| SUBSTRING('ééééé', 1, 3)      |
+-------------------------------+
| ééé                           |
+-------------------------------+

到目前为止,一切正常,让我们将连接切换为latin1编码。

MySQL [hozana]> set names latin1;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SELECT SUBSTRING('ééééé', 1, 3);
+-------------------------------+
| SUBSTRING('ééééé', 1, 3)      |
+-------------------------------+
| é�                             |
+-------------------------------+

我现在发现的唯一方法是在函数SUBSTRING()之前将字符串转换为utf-8,然后再将其转换回latin1。太丑了...

MySQL [hozana]> select convert(cast(convert(substring(convert(cast(convert('éééé' using  latin1) as binary) using utf8), 1, 3) using utf8) as binary) using latin1);
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| convert(cast(convert(substring(convert(cast(convert('éééé' using  latin1) as binary) using utf8), 1, 3) using utf8) as binary) using latin1)     |
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| ééé                                                                                                                                              |
+--------------------------------------------------------------------------------------------------------------------------------------------------+

我的问题是,要使SUBSTRING()latin1中工作,应该进行正确的配置吗?

注意

这是set names之前和之后的配置:

MySQL [hozana]> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.5.54    |
+-----------+

MySQL [hozana]> set names utf8;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SHOW SESSION VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | utf8   |
| character_set_connection | utf8   |
| character_set_database   | latin1 |
| character_set_filesystem | binary |
| character_set_results    | utf8   |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+

MySQL [hozana]> set names latin1;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SHOW SESSION VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | latin1 |
| character_set_connection | latin1 |
| character_set_database   | latin1 |
| character_set_filesystem | binary |
| character_set_results    | latin1 |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+

1 个答案:

答案 0 :(得分:0)

用户错误。

当您说SET NAMES latin1时,您是在向MySQL宣布来自客户端(您)的字节是用latin1编码的。但事实并非如此。他们仍然在utf8中。

当您键入ééééé时,生成的字节是这些 10 字节C3A9C3A9C3A9C3A9C3A9,这些字节以 10 latin1个字符发送到mysql,即{ {1}}。 ééééé根据要求删除了前3个字符(但它们是latin1个字符:SUBSTRING,十六进制éÃ,然后将它们传送回您的UTF-8客户程序,该客户程序开始解释{ {1}}为C3A9C3,然后插在无效的UTF-8,十六进制C3上,并用黑色菱形C3A9(“替换字符”)在终端上插入。

因此,始终要确保通过连接机制中的某些内容或使用é建立客户端的编码。如果指定不正确,可能会发生各种各样的不良情况。 {this不能直接解决您的问题;但它解决了许多可能发生的其他事情。

哦,另一件事。您说您拥有“带有latin1编码的MySQL数据库”。那没问题。您仍然必须指定(显然)SET NAMES编码的客户端。当您执行utf8时,MySQL将转换为的编码,而当您执行utf8mb4时,MySQL将以另一种方式转换回。由于INSERTSELECT中都存在é(对于所有其他西欧带重音符号的字母也是如此),所以一切都应该很好。

也许您用文字来编写问题。好吧,这不一定反映表中的latin1。因此,我精心制作了一个表,其中既包含latin1列又包含utf8列,每个列均包含utf8,并验证了十六进制和LENGTH是不同的。然后在两种情况下测试SELECTing都会正确产生ééééé