MySQL:SELECT INTO使用的字符编码?
我正试图从MySQL数据库中导出一些数据,但该表中的unicode发生了奇怪而奇妙的事情 我将关注一个字符,左边的smartquote:“ 当我使用控制台中的MySQL:SELECT INTO使用的字符编码?,mysql,utf-8,character-encoding,Mysql,Utf 8,Character Encoding,我正试图从MySQL数据库中导出一些数据,但该表中的unicode发生了奇怪而奇妙的事情 我将关注一个字符,左边的smartquote:“ 当我使用控制台中的选择时,它将无问题打印: mysql> SELECT text FROM posts; +-------+ | text | +-------+ | “foo” | +-------+ 这意味着数据将以utf-8[0]的形式发送到我的终端(这是正确的) 但是,当我使用SELECT*FROM posts to OUTFILE'/tm
选择时,它将无问题打印:
mysql> SELECT text FROM posts;
+-------+
| text |
+-------+
| “foo” |
+-------+
这意味着数据将以utf-8[0]的形式发送到我的终端(这是正确的)
但是,当我使用SELECT*FROM posts to OUTFILE'/tmp/x.csv'…;
时,输出文件的编码不正确:
$ cat /tmp/x.csv
“fooâ€
具体来说,“
用七(7!)个字节编码:\xc3\xa2\xe2\x82\xac\xc5\x93
这是什么编码?或者我如何告诉MySQL使用不太合理的编码
此外,还有一些杂项事实:
SELECT@@character\u set\u数据库
返回latin1
text
列是一个VARCHAR(42)
:
mysql>描述帖子;
+-------+-------------+------+-----+---------+-------+
|字段|类型|空|键|默认|额外|
+-------+-------------+------+-----+---------+-------+
|文本| varchar(42)| NO | MUL ||
+-------+-------------+------+-----+---------+-------+
“
编码为utf-8产生\xe2\x80\x9c
\xe2\x80\x9c
解码为latin1
,然后重新编码为utf-8
产生\xc3\xa2\xc2\x80\xc2\x9c
(6字节)
- 另一个数据点:
…
(utf-8:\xe2\x80\xa6
)编码为\xc3\xa2\xe2\x82\xac\xc2\xa6
[0]:由于智能引号不包含在任何8位编码中,并且我的终端正确呈现utf-8字符。在运行SELECT
之前,您需要在MySQL提示符下发出charset utf8
。这会告诉服务器输出结果的内容。在选择之前尝试设置字符集
,=utf8de>或拉丁语1
等。。。
见:
或者设置名称utf8;
可能有用…为了具体解决您的问题“这是什么?”,您自己已经回答了:
我怀疑这是因为“列值使用二进制字符集转储。实际上,没有字符集转换。”-dev.mysql.com/doc/refman/5.0/en/select-into.html
这就是MySQL内部存储utf8
编码数据的方式。这是一种效率极低的Unicode存储变体,显然对大多数字符使用了整整三个字节,并且不支持四字节UTF-8序列
至于如何使用转换为OUTFILE
将其转换为真正的UTF-8,我不知道。不过,使用其他mysqldump
方法可以做到这一点。您可以使用CLI工具执行MySQL查询(我相信即使使用输出格式,它也会打印出CSV)应该进行字符集转换,并且仍然允许访问连接,等等。 < p>许多程序/标准(包括MySQL)假设“LATIN1”是“CP1252”,因此0x80字节被解释为一个欧元符号,这就是<代码> \xE2\x82\xac >位(u+20ac)从中间来的地方。
当我尝试此操作时,它工作正常(但请注意我是如何将数据放入的,以及db服务器上设置的变量):
从外壳上看:
/tmp$ hexdump -C x.csv
00000000 e2 80 9c 0a |....|
00000004
希望这里有一个有用的小贴士…正如您所看到的,我的MySQL数据库使用的是latin1
,系统是utf-8
mysql>显示诸如“character\\u set\\u%”之类的变量;
+--------------------------+--------+
|变量名称|值|
+--------------------------+--------+
|字符集客户机拉丁1|
|字符集连接拉丁1|
|字符集数据库拉丁1|
|字符集文件系统二进制|
|字符集结果拉丁1|
|字符集服务器拉丁1|
|字符集系统utf8|
+--------------------------+--------+
一组7行(0.00秒)
每次我尝试导出表时,都会得到奇怪的编码CSV文件。
因此,我提出:
mysql_query("SET NAMES CP1252");
header('Content-Type: text/csv; charset=cp1252');
header('Content-Disposition: attachment;filename=output.csv');
就像在我的生活中一样
然后我得到了纯UTF-8输出。我发现这很有效
SELECT convert(col_name USING latin1) FROM posts INTO OUTFILE '/tmp/x.csv' …;
MySQL的较新版本有一个选项,可以在outfile子句中设置字符集:
SELECT col1,col2,col3
FROM table1
INTO OUTFILE '/tmp/out.txt'
CHARACTER SET utf8
FIELDS TERMINATED BY ','
为什么要使用这个,而不是mysqldump?!我使用了选择进入
,因为我想在导出之前过滤并加入数据。不过,我可能不需要这样做……因为有些数据比完全破坏的数据要好。你可以克隆数据库,并对克隆进行必要的更新,以获得所需的导出。这是可行的…但在这一点上,我想我只是要写一个小Python脚本来为我做转储。我想知道为什么我们通常围绕这个问题,而不是解决它。这不会改变结果。您得到的结果与没有它的结果相同?或者您得到的结果不同,但仍然不正确。并且设置charset-latin1
doesn也不会更改结果。我得到了相同的结果。我怀疑这是因为“列值使用二进制字符集转储。实际上,没有字符集转换。”-啊…嗯…那么,出于好奇,MySQL是如何在内部编码unicode数据的?我希望我知道。我在写这个答案时翻阅了文档,但找不到任何具体内容。它不是UCS-2,不是UTF-8,也不是UTF-16。我只是对MySQL的“UTF-8”有着挥之不去的被动认识存储不是UTF-8,也不是很优化。可能值得提出一个新问题。因此,文档似乎在撒谎(或者至少是误导)。@taavi似乎找到了答案-MySQL的“latin1”实际上是cp1252,所以MySQL将文本解码为cp1252,然后将其编码为UTF-8。太棒了!答对了。就是这样:“\xe2\x80\x9c”.解码(“cp1252”).编码(“utf-8”)
产生“\xc3\xa2\xe2\x82\xac\xc5\x93”
。谢谢!如果我在这里错了,请纠正我,但这意味着
SELECT convert(col_name USING latin1) FROM posts INTO OUTFILE '/tmp/x.csv' …;
SELECT col1,col2,col3
FROM table1
INTO OUTFILE '/tmp/out.txt'
CHARACTER SET utf8
FIELDS TERMINATED BY ','