A importação de dados latin1 para MySQL está sendo truncada

Eu estava tendo um problema esta semana, ao tentar fazer upload de dados com chars ‘especiais’ no MySQL 5.1, usando Ruby on Rails.

Os dados estavam apenas sendo truncados conforme descrito neste tópico .

Havia muitos lugares onde esse problema poderia ser:

  • Configuração do banco de dados Ruby on Rails;

  • O MySQL 5.1 pode ter algum tipo de bug, como a consulta a seguir não funcionou para mim SHOW COLLATION LIKE 'latin1%';

  • a sintaxe de ‘LOAD DATA INFILE’ pode estar errada

A solução

Eu tentei e tentei, estava sendo doloroso. Resolvi ligar para meu grande amigo@Lynx_Eyes que me disse exatamente onde estava o problema, no charset CSV ! Portanto, a única coisa necessária é corrigir o próprio CSV.

Então aqui vai minha solução:

1. Altere o script de importação do MySQL

No script RoR / MySQL que acabei de adicionar CHARACTER SET 'utf8'após oINTO TABLE

# Load the import SQL statment from file & set some variables
import_csv_sql
= <<-SQL
LOAD DATA LOCAL INFILE
'#{csv_data_file_path}'
INTO TABLE
#{mysql_table_name} CHARACTER SET 'utf8'
FIELDS

TERMINATED BY
','
ENCLOSED BY
'"'
LINES

TERMINATED BY
'\n'
(
#{column_headers.map{|c| c.name}.join(",n")}
);
SQL

2. converta o arquivo CSV

Observe que neste projeto estamos usando o Ruby 1.8.7 antigo e obsoleto.

Então criei um módulo para pré-processar o arquivo CSV antes de ser passado para o MySQL.

No shell, você precisa primeiro descobrir qual é o conjunto de caracteres atual do seu arquivo CSV. O comando file irá ajudá-lo com isso:

2.1 Execute $ file -ib <filename>no prompt de comando, isso retornará algo assim:

application/octet-stream; charset=binary

ou

application/octet-stream; charset=iso-8859-1

No Ruby 2.0.0, isso é facilmente alcançado usando o método IO #external_encoding

2.2 Agora, use o resultado que você obteve como parâmetro para o iconv. Por padrão, o iconv passa para STDOUT, então é melhor redirecionar a saída para um novo arquivo, algo como este:

iconv --from-code=iso-8859-1 --to-code=utf-8 <input_file> --output=<output_file>

Você pode verificar meu módulo na essência que criei.

Como observação lateral, descobri que a versão fileinfluencia o resultado. No meu ambiente de desenvolvimento tenho a versão 5.11 que dá o resultado acima. Eu testei com uma versão mais antiga (arquivo-4.17) que infelizmente não retorna o conjunto de caracteres.