web-dev-qa-db-ja.com

データベースのデフォルトの照合を変更する方法は?

前のプログラマーはテーブル(Mysql)に間違った照合を設定しました。彼は、UTF8である必要があるときに、ラテン語照合でセットアップしましたが、今は問題があります。中国語と日本のキャラクターを含むすべてのレコードが???になります。キャラクター。

照合順序を変更して、キャラクターの詳細を取り戻すことは可能ですか?

150
Jeg Bagus

データベース照合の変更:

ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;

テーブル照合を変更します。

ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

列の照合順序を変更します。

ALTER TABLE <table_name> MODIFY <column_name> VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci;

詳細:

334
Timo Huovinen

すべてのデータベース/テーブル/列を変更する方法をここに示します。これらのクエリを実行すると、スキーマ全体をutf8に変換するために必要な後続のクエリがすべて出力されます。お役に立てれば!

-データベースのデフォルト照合の変更

SELECT DISTINCT concat('ALTER DATABASE `', TABLE_SCHEMA, '` CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.tables
where TABLE_SCHEMA like  'database_name';

-テーブル照合/文字セットの変更

SELECT concat('ALTER TABLE `', TABLE_SCHEMA, '`.`', table_name, '` CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.tables
where TABLE_SCHEMA like 'database_name';

-COLUMN照合/文字セットの変更

SELECT concat('ALTER TABLE `', t1.TABLE_SCHEMA, '`.`', t1.table_name, '` MODIFY `', t1.column_name, '` ', t1.data_type , '(' , t1.CHARACTER_MAXIMUM_LENGTH , ')' , ' CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.columns t1
where t1.TABLE_SCHEMA like 'database_name' and t1.COLLATION_NAME = 'old_charset_name';
42
David Whittaker

Mysqlでは、utf8文字セットは実際のUTF8文字セットのサブセットにすぎないことに注意してください。 1バイトのストレージを節約するために、Mysqlチームは、完全な4バイトではなく、3バイトのUTF8文字のみを保存することにしました。つまり、一部の東アジア言語と絵文字は完全にはサポートされていません。すべてのUTF8文字を保存できるようにするには、utf8mb4データ型と、Mysqlでutf8mb4_binまたはutf8mb4_general_ciを使用します。

23
bluecollarcoder

David Whittakerが投稿したものに加えて、各テーブルを変換する完全なテーブルおよび列のALTERステートメントを生成するクエリを作成しました。実行することをお勧めします

SET SESSION group_concat_max_len = 100000;

まず、グループ連結が here のように非常に小さな制限を超えないようにします。

     SELECT a.table_name, concat('ALTER TABLE ', a.table_schema, '.', a.table_name, ' DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci, ',
        group_concat(distinct(concat(' MODIFY ',  column_name, ' ', column_type, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ', if (is_nullable = 'NO', ' NOT', ''), ' NULL ',
        if (COLUMN_DEFAULT is not null, CONCAT(' DEFAULT \'', COLUMN_DEFAULT, '\''), ''), if (EXTRA != '', CONCAT(' ', EXTRA), '')))), ';') as alter_statement
    FROM information_schema.columns a
    INNER JOIN INFORMATION_SCHEMA.TABLES b ON a.TABLE_CATALOG = b.TABLE_CATALOG
        AND a.TABLE_SCHEMA = b.TABLE_SCHEMA
        AND a.TABLE_NAME = b.TABLE_NAME
        AND b.table_type != 'view'
    WHERE a.table_schema = ? and (collation_name = 'latin1_swedish_ci' or collation_name = 'utf8mb4_general_ci')
    GROUP BY table_name;

ここでの以前の回答との違いは、ut8mb4の代わりにutf8を使用し、t1.CHARACTER_MAXIMUM_LENGTHでt1.data_typeを使用すると列挙型で機能しなかったことです。また、ビューは個別に変更する必要があるため、クエリはビューを除外します。

私は単にPerlスクリプトを使用してこれらのすべての変更を配列として返し、それらを反復し、長すぎる列を修正しました(通常、データに20文字しか含まれていない場合はvarchar(256)だったため、簡単に修正できました) )。

Latin1-> utf8mb4から変更すると、一部のデータが破損していることがわかりました。 utf8でエンコードされた列のlatin1文字は、変換時に不正になります。変更前と変更後のメモリで問題になるとわかっていた列のデータを保持し、それらを比較してデータを修正する更新ステートメントを生成しました。

6
Jacob Hundley

here はプロセスをよく説明しています。ただし、ラテン語のスペースに収まらなかったキャラクターの一部は永遠に消えてしまいます。 UTF-8はlatin1のスーパーセットです。逆ではありません。ほとんどはシングルバイトスペースに収まりますが、未定義のものは収まりません(latin1のリストを確認してください-mysqlのlatin1の定義によっては、256文字すべてが定義されているわけではありません)

4
MJB