12

私は大規模な古い 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つのステップで行うエレガントな方法を知っていれば、私はまだ答えを受け入れます。

4

1 に答える 1

13

以下のこの方法は、非常に有望であり、さらに優れているように見えますが、そのシンプルさは美しいです。アイデアは、データベース全体を latin1 として mysqldump し、utf-8 として再エンコードしてインポートすることです。

書き出す:

mysqldump -u [ユーザー] -p --opt --quote-names --skip-set-charset --default-character-set=latin1 [データベース] > dump.sql

輸入:

mysql -u [ユーザー] -p --default-character-set=utf8 [データベース] < dump.sql

このソリューションの功績は認めません。完全にGareth Price のブログから引用したものです。これまでに彼にコメントを残したすべての人にとって、それはうまくいきました

更新 #1:これを発見したのはガレスが最初ではなかったようです。

更新 #2:これを試してみたところ、UTF8-store-as-latin1 データベースで美しく機能しました。インポートする前に、データベースのデフォルトの文字セットを utf8 に切り替えてください。そうしないと、特殊文字があった場所に単純な疑問符が表示されます。もちろん、これには他にも多くの影響がある可能性があるため、最初に徹底的にテストしてください。

ALTER SCHEMA [データベース] DEFAULT CHARACTER SET utf8;

また、スキーマのデフォルトに設定されていないテーブルがある場合:

ALTER TABLE [テーブル] CHARACTER SET = DEFAULT;

(列固有の文字セット設定がある場合と同じ考えで、CHARACTER SETを指定せずに ALTER TABLE [table] CHANGE COLUMN [settings]を実行する必要があるため、テーブルのデフォルトに戻ります)

于 2014-03-28T18:11:31.383 に答える