Преобразование таблицы MySQL с неправильно закодированными данными в UTF-8

У меня есть большая база данных MySQL 5.1, и по разным причинам глупо, я считаю, что символы UTF8 кодируются как LATIN1 в таблице UTF8. Странно. И я хотел бы исправить это.

MySQL - конвертировать символы latin1 в таблицу UTF8 в UTF8, кажется, работает - столбец за раз. Но у меня есть 24 таблицы и десятки столбцов для конвертирования. Я действительно ищу решение, которое будет конвертировать хотя бы таблицу сразу.

Для справки, одноколоночное решение, которое работает для меня, это:

UPDATE foo SET col1 = CONVERT(CAST(CONVERT(col1 USING latin1) AS binary) USING utf8);

Для таблиц я могу сделать:

ALTER TABLE foo CONVERT TO CHARACTER SET latin1;
ALTER TABLE foo CONVERT TO CHARACTER SET binary;
ALTER TABLE foo CHARACTER SET utf8  COLLATE utf8_unicode_ci;

который меня очень близко, однако шаг CONVERT TO CHARACTER SET binary превращает все мои столбцы VARCHAR в VARBINARY и мои столбцы TEXT в BLOB одним махом. Я могу пройти и изменить их обратно, и все, кажется, хорошо... но потом я вернулся в мир "разрешить изменение всех столбцов по отдельности", и в этом случае я также могу

Я пробовал около 50 вариантов этих операторов SQL, но не могу найти тот, который оставляет мои столбцы в символьных типах данных и правильно кодирует данные.

Любые предложения?

Обновление: Решив просто исправить столбцы, а не ждать решения для базы данных или таблиц, я придумал:

#!/usr/bin/env ruby
require 'rubygems'
require 'mysql2'

CONNECT_OPTS = {} # whatever you want
Mysql2::Client.default_query_options.merge!(:as => :array)
conn = Mysql2::Client.new(CONNECT_OPTS)

tables = conn.query("SHOW TABLES").map {|row| row[0] }

# See http://dev.mysql.com/doc/refman/5.0/en/charset-column.html
# One might want to include enum and set columns; I don't have them
TYPES_TO_CONVERT = %w(char varchar text)
tables.each do |table|
  puts "converting #{table}"
  # Get all the columns and we'll filter for the ones we want
  columns = conn.query("DESCRIBE #{table}")
  columns_to_convert = columns.find_all {|row|
    TYPES_TO_CONVERT.include? row[1].gsub(/\(\d+\)/, '')
  }.map {|row| row[0]}
  next if columns_to_convert.empty?

  query = "UPDATE `#{table}` SET "
  query += columns_to_convert.map {|col|
    "`#{col}` = convert(cast(convert(`#{col}` using latin1) as binary) using utf8)"
  }.join ", "
  puts query
  conn.query query
end

... который выполняет свою работу. Поразительно, что это работает в моей базе данных за 36 секунд, а не в маршруте ALTER TABLE, который занял 13 минут (и имел проблему VARBINARY) или решения mysqldump, которые занимали бы свыше двадцати, предполагая, что я могу заставить их работать.

Я все равно соглашусь ответить, если кто-то знает элегантный способ сделать это для всей базы данных или таблицы за один шаг.

Ответ 1

Этот метод ниже выглядит действительно многообещающим и еще лучше, красивым по своей простоте. Идея заключается в том, что вы mysqldump всю свою базу данных как latin1, а затем импортируете ее повторно кодированной как utf-8.

Экспорт

mysqldump -u [user] -p --opt --quote-names --skip-set-charset --default-character-set = latin1 [database] > dump.sql

Импорт

mysql -u [user] -p --default-character-set = utf8 [database] < dump.sql

Я не беру на себя ответственность за это решение, это полностью из Gareth Price blog. Он работал для всех, кто оставил ему комментарий до сих пор: "Ничего себе, ты просто спас мне жизнь. Я не потратил на это 2 часа, но 2 дня" привлек мое внимание.

Обновление # 1: Похоже, Gareth не был первым, чтобы обнаружить это.

Обновление # 2: Я просто попробовал это, и он отлично работал для моей базы данных UTF8-stored-as-latin1. Просто убедитесь, что вы переключили кодировку по умолчанию в своей базе данных на utf8 перед импортом, иначе вы получите простые вопросительные знаки, где были специальные символы. Конечно, это может иметь много других последствий, поэтому сначала проверьте, как ад.

ALTER SCHEMA [база данных] УКАЗАТЕЛЬ ПО УМОЛЧАНИЮ SET ut8;

И если у вас есть таблицы, которые не установлены для схемы по умолчанию:

ALTER TABLE [таблица] CHARACTER SET = DEFAULT;

(та же идея, если у вас есть какие-либо настройки набора символов для столбца, вам нужно будет сделать ALTER TABLE [table] CHANGE COLUMN [settings] без указания CHARACTER SET, чтобы он возвращался к таблице по умолчанию)