私は大規模な古い MySQL 5.1 データベースを持っており、さまざまな愚かな理由で、UTF8 テーブルに LATIN1 としてエンコードされた UTF8 文字を格納していると思います。それは奇妙です。で、直したいと思います。
MySQL - Convert latin1 characters on a UTF8 table into UTF8 の質問は、一度に 1 列ずつ機能しているようです。しかし、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 に変換されます。やり直して元に戻すと、すべて問題ないように見えますが、「すべての列を個別に変更してみましょう」という世界に戻ってしまいます。
これらの SQL ステートメントで約 50 のバリエーションを試しましたが、列を文字データ型のままにし、データを適切にエンコードするものを見つけることができません。
助言がありますか?
更新:データベースまたはテーブルごとの解決策を待つのではなく、列を修正することに決めたので、次のように思いつきました。
#!/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 秒で実行されます。13 分かかった (そして VARBINARY 問題があった) ALTER TABLE ルートや、実行できると仮定すると 20 回以上かかる mysqldump ソリューションではありません。
誰かがデータベースまたはテーブル全体に対してこれを1つのステップで行うエレガントな方法を知っていれば、私はまだ答えを受け入れます。