MySQL: кодировка символов, используемая SELECT INTO? - PullRequest
23 голосов
/ 19 марта 2012

Я пытаюсь экспортировать некоторые данные из базы данных MySQL, но с юникодом в этой таблице происходят странные и удивительные вещи.

Я остановлюсь на одном символе, левой умной цитате: «

Когда я использую SELECT с консоли, он печатается без проблем:

mysql> SELECT text FROM posts;
+-------+
| text  |
+-------+
| “foo” |
+-------+

Это означает, что данные отправляются на мой терминал как utf-8 [0] (что правильно).

Однако, когда я использую SELECT * FROM posts INTO OUTFILE '/tmp/x.csv' …;, выходной файл не правильно закодирован:

$ cat /tmp/x.csv
“fooâ€

В частности, кодируется семью (7!) Байт: \xc3\xa2\xe2\x82\xac\xc5\x93.

Какая это кодировка?Или как я могу сказать MySQL использовать менее необоснованную кодировку?

Кроме того, некоторые разные факты:

  • SELECT @@character_set_database возвращает latin1
  • text столбец - VARCHAR(42): mysql> DESCRIBE posts; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | text | 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.

Ответы [ 8 ]

24 голосов
/ 11 февраля 2013

Более новые версии MySQL имеют возможность установить набор символов в предложении outfile:

SELECT col1,col2,col3 
FROM table1 
INTO OUTFILE '/tmp/out.txt' 
CHARACTER SET utf8
FIELDS TERMINATED BY ','
6 голосов
/ 19 марта 2012

Многие программы / стандарты (в том числе MySQL) предполагают, что «latin1» означает «cp1252», поэтому байт 0x80 интерпретируется как символ евро, отсюда и происходит этот \xe2\x82\xac бит (U + 20AC) в середине. .

Когда я пытаюсь это сделать, это работает правильно (но обратите внимание, как я помещаю данные и переменные, установленные на сервере БД):

mysql> set names utf8; -- http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html
mysql> create table sq (c varchar(10)) character set utf8;
mysql> show create table sq\G
*************************** 1. row ***************************
       Table: sq
Create Table: CREATE TABLE `sq` (
  `c` varchar(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.19 sec)

mysql> insert into sq values (unhex('E2809C'));
Query OK, 1 row affected (0.00 sec)

mysql> select hex(c), c from sq;
+--------+------+
| hex(c) | c    |
+--------+------+
| E2809C | “  |
+--------+------+
1 row in set (0.00 sec)

mysql> select * from sq into outfile '/tmp/x.csv';
Query OK, 1 row affected (0.02 sec)

mysql> show variables like "%char%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       | 
| character_set_connection | utf8                       | 
| character_set_database   | utf8                       | 
| character_set_filesystem | binary                     | 
| character_set_results    | utf8                       | 
| character_set_server     | latin1                     | 
| character_set_system     | utf8                       | 
| character_sets_dir       | /usr/share/mysql/charsets/ | 
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

А из скорлупы:

/tmp$ hexdump -C x.csv
00000000  e2 80 9c 0a                                       |....|
00000004

Надеюсь, там есть полезная информация ...

3 голосов
/ 28 января 2013

Я обнаружил, что это хорошо работает.

SELECT convert(col_name USING latin1) FROM posts INTO OUTFILE '/tmp/x.csv' …;
2 голосов
/ 22 сентября 2012

Как вы можете видеть, моя база данных MySQL использует latin1, а система utf-8.

mysql> SHOW 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   |
+--------------------------+--------+
7 rows in set (0.00 sec)

Каждый раз, когда я пытался экспортировать таблицу, я получал странный кодированный файл CSV. Итак, я положил:

mysql_query("SET NAMES CP1252");
header('Content-Type: text/csv; charset=cp1252');
header('Content-Disposition: attachment;filename=output.csv');

как в моем экспортном скрипте .

Тогда у меня есть чистый вывод UTF-8.

2 голосов
/ 19 марта 2012

Чтобы конкретно ответить на ваш вопрос «Что это?», Вы сами на него ответили:

Я подозреваю, что это потому, что «Значения столбцов сбрасываются с использованием двоичного набора символов.По сути, преобразование набора символов отсутствует ». - dev.mysql.com/doc/refman/5.0/en/select-into.html

Именно так MySQL хранит закодированные символы utf8данные внутри.Это ужасно неэффективный вариант хранения Unicode, по-видимому, использующий три байта для большинства символов и не поддерживающий четырехбайтовые последовательности UTF-8.

Что касается того, как преобразовать его в настоящий UTF-8, используя INTO OUTFILE... Я не знаю.Использование других методов mysqldump сделает это.

1 голос
/ 19 марта 2012

Вы можете выполнять запросы MySQL с помощью инструмента CLI (я полагаю, даже с выходным форматом, поэтому он печатает CSV) и перенаправлять в файл.Должен выполнять преобразование кодировки и по-прежнему предоставлять вам доступ к объединениям и т. Д.

1 голос
/ 19 марта 2012

Попробуйте SET CHARACTER SET <blah> перед вашим выбором, <blah>=utf8 или latin1 и т. Д ... См .: http://dev.mysql.com/doc/refman/5.6/en/charset-connection.html

Или SET NAMES utf8; может работать ...

0 голосов
/ 19 марта 2012

Вам нужно ввести charset utf8 в командной строке MySQL перед запуском SELECT. Это сообщает серверу, что выводить результаты как.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...