У меня есть большая база данных 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, которые занимали бы свыше двадцати, предполагая, что я могу заставить их работать.
Я все равно соглашусь ответить, если кто-то знает элегантный способ сделать это для всей базы данных или таблицы за один шаг.