web-dev-qa-db-fra.com

MySQL: encodage de caractères utilisé par SELECT INTO?

J'essaie d'exporter certaines données d'une base de données MySQL, mais des choses étranges et merveilleuses se produisent pour unicode dans cette table.

Je vais me concentrer sur un personnage, la smartquote de gauche: "

Lorsque j'utilise SELECT depuis la console, il est imprimé sans problème:

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

Cela signifie que les données sont envoyées à mon terminal en tant que utf-8 [0] (ce qui est correct).

Cependant, lorsque j'utilise SELECT * FROM posts INTO OUTFILE '/tmp/x.csv' …;, Le fichier de sortie est pas correctement codé:

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

Plus précisément, le Est codé avec sept (7!) Octets: \xc3\xa2\xe2\x82\xac\xc5\x93.

De quel encodage s'agit-il? Ou comment pourrais-je dire à MySQL d'utiliser un encodage moins déraisonnable?

En outre, quelques faits divers:

  • SELECT @@character_set_database Renvoie latin1
  • La colonne text est une VARCHAR(42):
    
    mysql> DESCRIBE posts;
    +-------+-------------+------+-----+---------+-------+
    | Field | Type        | Null | Key | Default | Extra |
    +-------+-------------+------+-----+---------+-------+
    | text  | varchar(42) | NO   | MUL |         |       |
    +-------+-------------+------+-----+---------+-------+
    
  • Encodé en utf-8 donne \xe2\x80\x9c
  • \xe2\x80\x9c Décodé en latin1 Puis recodé en utf-8 Donne \xc3\xa2\xc2\x80\xc2\x9c (6 octets).
  • Un autre point de données: (Utf-8: \xe2\x80\xa6) Est codé en \xc3\xa2\xe2\x82\xac\xc2\xa6

[0]: comme les guillemets intelligents ne sont inclus dans aucun encodage 8 bits, et mon terminal affiche correctement les caractères utf-8.

23
David Wolever

De nombreux programmes/normes (y compris MySQL) supposent que "latin1" signifie "cp1252", donc l'octet 0x80 est interprété comme un symbole Euro, c'est là que ce \xe2\x82\xac le bit (U + 20AC) vient du milieu.

Lorsque j'essaie, cela fonctionne correctement (mais notez comment je mets les données et les variables définies sur le serveur db):

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)

Et depuis le Shell:

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

J'espère qu'il y a une friandise utile là-dedans…

6
taavi

Les versions plus récentes de MySQL ont une option pour définir le jeu de caractères dans la clause outfile:

SELECT col1,col2,col3 
FROM table1 
INTO OUTFILE '/tmp/out.txt' 
CHARACTER SET utf8
FIELDS TERMINATED BY ','
24
mvd

J'ai trouvé que cela fonctionne bien.

SELECT convert(col_name USING latin1) FROM posts INTO OUTFILE '/tmp/x.csv' …;
3
dhruvbird

Comme vous pouvez le voir, ma base de données MySQL utilise latin1 et le système est 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)

Chaque fois que j'essayais d'exporter une table, j'obtenais un étrange fichier CSV encodé. Donc, je mets:

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

comme dans mon script d'exportation .

Ensuite, j'ai une sortie UTF-8 pure.

2
paczor

Pour répondre spécifiquement à votre question "Qu'est-ce que c'est?", Vous y avez répondu vous-même:

Je soupçonne que cela est dû au fait que "les valeurs des colonnes sont vidées à l'aide du jeu de caractères binaires. En effet, il n'y a pas de conversion de jeu de caractères. "- dev.mysql.com/doc/refman/5.0/en/select-into.html

C'est ainsi que MySQL stocke utf8 données encodées en interne. C'est une variation terriblement inefficace du stockage Unicode, utilisant apparemment trois octets complets pour la plupart des caractères, et ne prenant pas en charge les séquences UTF-8 de quatre octets.

Quant à savoir comment le convertir en UTF-8 réel en utilisant INTO OUTFILE... Je ne sais pas. L'utilisation d'autres méthodes mysqldump le fera cependant.

2
deceze

Vous pouvez exécuter des requêtes MySQL à l'aide de l'outil CLI (je crois même avec un format de sortie pour qu'il imprime CSV) et rediriger vers un fichier. Devrait faire la conversion de jeu de caractères et vous donner toujours accès aux jointures, etc.

1
singpolyma

Essayez SET CHARACTER SET <blah> avant votre sélection, <blah>=utf8 ou latin1 etc ... Voir: http://dev.mysql.com/doc/refman/5.6/en/charset-connection.html

Ou SET NAMES utf8; pourrait fonctionner...

1
Hardeep

Vous devez émettre charset utf8 à l'invite MySQL avant d'exécuter le SELECT. Cela indique au serveur sous quelle forme les résultats doivent être affichés.

0
Burhan Khalid