回答:
私のガイド「MySQLデータベースで完全なUnicodeをサポートする方法」から、データベース、テーブル、または列の文字セットと照合順序を更新するために実行できるクエリを次に示します。
各データベースについて:
ALTER DATABASE
database_name
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
各テーブルについて:
ALTER TABLE
table_name
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
各列について:
ALTER TABLE
table_name
CHANGE column_name column_name
VARCHAR(191)
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
(盲目的にこれをコピーして貼り付けないでください!正確なステートメントは、列のタイプ、最大長、およびその他のプロパティによって異なります。上記の行はVARCHAR
列の単なる例です。)
ただし、からutf8
への変換を完全に自動化することはできませんutf8mb4
。上記のガイドのステップ4で説明されているように、指定する数値utf8mb4
はの代わりに使用されると異なる意味を持つため、列とインデックスキーの最大長を確認する必要がありますutf8
。
MySQL 5.5リファレンスマニュアルのセクション10.1.11には、これに関するいくつかの情報があります。
いくつかのコマンドを実行してデータベースとテーブルを変換するソリューションがあります。また、タイプのすべての列を変換しvarchar
、text
、tinytext
、mediumtext
、longtext
、char
。また、何かが壊れた場合に備えてデータベースをバックアップする必要があります。
次のコードをpreAlterTables.sqlというファイルにコピーします。
use information_schema;
SELECT concat("ALTER DATABASE `",table_schema,"` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;") as _sql
FROM `TABLES` where table_schema like "yourDbName" group by table_schema;
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name,"` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as _sql
FROM `TABLES` where table_schema like "yourDbName" group by table_schema, table_name;
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column_name,"` `",column_name,"` ",data_type,"(",character_maximum_length,") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",IF(is_nullable="YES"," NULL"," NOT NULL"),";") as _sql
FROM `COLUMNS` where table_schema like "yourDbName" and data_type in ('varchar','char');
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column_name,"` `",column_name,"` ",data_type," CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",IF(is_nullable="YES"," NULL"," NOT NULL"),";") as _sql
FROM `COLUMNS` where table_schema like "yourDbName" and data_type in ('text','tinytext','mediumtext','longtext');
「yourDbName」の出現箇所をすべて、変換するデータベースに置き換えます。次に実行します:
mysql -uroot < preAlterTables.sql | egrep '^ALTER' > alterTables.sql
これにより、データベースを変換するために必要なすべてのクエリを含む新しいファイルalterTables.sqlが生成されます。次のコマンドを実行して、変換を開始します。
mysql -uroot < alterTables.sql
table_schemaの条件を変更することで、複数のデータベースを実行するようにこれを調整することもできます。たとえばtable_schema like "wiki_%"
、名前がprefixであるすべてのデータベースを変換しますwiki_
。すべてのデータベースを変換するには、条件をに置き換えますtable_type!='SYSTEM VIEW'
。
発生する可能性のある問題。mysqlキーにvarchar(255)列がいくつかありました。これによりエラーが発生します。
ERROR 1071 (42000) at line 2229: Specified key was too long; max key length is 767 bytes
その場合は、varchar(150)のように列を小さくして、コマンドを再実行するだけです。
注:この回答は、質問で尋ねられたのutf8mb4_unicode_ci
代わりにデータベースを変換しますutf8mb4_bin
。しかし、これを単に置き換えることができます。
次のシェルスクリプトを使用しました。データベース名をパラメーターとして受け取り、すべてのテーブルを別の文字セットと照合順序に変換します(別のパラメーターまたはスクリプトで定義された既定値によって与えられます)。
#!/bin/bash
# mycollate.sh <database> [<charset> <collation>]
# changes MySQL/MariaDB charset and collation for one database - all tables and
# all columns in all tables
DB="$1"
CHARSET="$2"
COLL="$3"
[ -n "$DB" ] || exit 1
[ -n "$CHARSET" ] || CHARSET="utf8mb4"
[ -n "$COLL" ] || COLL="utf8mb4_general_ci"
echo $DB
echo "ALTER DATABASE \`$DB\` CHARACTER SET $CHARSET COLLATE $COLL;" | mysql
echo "USE \`$DB\`; SHOW TABLES;" | mysql -s | (
while read TABLE; do
echo $DB.$TABLE
echo "ALTER TABLE \`$TABLE\` CONVERT TO CHARACTER SET $CHARSET COLLATE $COLL;" | mysql $DB
done
)
この状況に突入しました。データベースを変換するために使用したアプローチは次のとおりです。
まず、my.cnf
デフォルトのデータベース接続(アプリケーションとMYSQLの間)utf8mb4_unicode_ciに準拠するように編集する必要があります。アプリが送信した絵文字などのこのような文字がないと、正しいバイト/エンコードでテーブルに到達しません(アプリケーションのDB CNNパラメーターがutf8mb4接続を指定していない限り)。
ここで与えられる指示。
次のSQLを実行します(個々の列を変更するために準備されたSQLを取得する必要ALTER TABLE
はありません。ステートメントで実行されます)。
以下のコードを実行する前に、「DbName」を実際のDB名に置き換えます。
USE information_schema;
SELECT concat("ALTER DATABASE `",table_schema,
"` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;") as _sql
FROM `TABLES`
WHERE table_schema like "DbName"
GROUP BY table_schema;
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name,
"` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as _sql
FROM `TABLES`
WHERE table_schema like "DbName"
GROUP BY table_schema, table_name;
上記のSQLの出力を収集し、ドットsqlファイルに保存して実行します。
#1071 - Specified key was too long; max key length is 1000 bytes.
問題のあるテーブル名とともにエラーが発生した場合、これは、そのテーブルの一部の列(MB4文字列に変換されるはずだった)のインデックスキーが非常に大きくなるため、Varchar列が<= 250である必要があることを意味しますインデックスキーは最大1000バイトです。インデックスがある列をチェックし、それらの1つが250以上(ほとんどの場合255)のvarcharである場合
ステップ1:その列のデータをチェックして、その列の最大文字列サイズが250以下であることを確認します。
クエリの例:
select `id`,`username`, `email`,
length(`username`) as l1,
char_length(`username`) as l2,
length(`email`) as l3,
char_length(`email`) as l4
from jos_users
order by l4 Desc;
ステップ2:インデックス付き列データの最大文字長が250以下の場合、列の長さを250に変更します。それが不可能な場合は、その列のインデックスを削除します
ステップ3:その後、そのテーブルに対してalter tableクエリを再度実行すると、テーブルがutf8mb4に正常に変換されるはずです。
乾杯!
私はこのガイドを書きました:http : //hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-character-set-to-utf8mb4
私の仕事から、データベースとテーブルのALTERでは不十分であることがわかりました。各テーブルに移動し、text / mediumtext / varcharの各列も変更する必要がありました。
幸いなことに、MySQLデータベースのメタデータを検出するスクリプトを作成できたため、テーブルと列をループしてそれらを自動的に変更できました。
MySQL 5.6の長いインデックス:
DBA / SUPER USER権限を持たなければならないことが1つあります。データベースパラメータの設定です。
innodb_large_prefix:ON innodb_file_format:バラクーダ innodb_file_format_max:バラクーダ
この質問の答えには、上記のパラメーターを設定する方法の説明があります:https : //stackoverflow.com/questions/35847015/mysql-change-innodb-large-prefix
もちろん、私の記事にはそれを行うための指示もあります。
MySQLバージョン5.7以降では、innodb_large_prefixはデフォルトでONであり、innodb_file_formatもデフォルトでBarracudaです。
この問題を抱えている可能性のある人にとって最良の解決策は、この表に従って、最初に列をバイナリ型に変更することです。
その後、列を変更して元の型に戻し、目的の文字セットを使用します。
例えば。:
ALTER TABLE [TABLE_SCHEMA].[TABLE_NAME] MODIFY [COLUMN_NAME] LONGBLOB;
ALTER TABLE [TABLE_SCHEMA].[TABLE_NAME] MODIFY [COLUMN_NAME] VARCHAR(140) CHARACTER SET utf8mb4;
いくつかのlatin1テーブルで試してみましたが、すべての発音区別符号が保持されていました。
これを行うすべての列に対してこのクエリを抽出できます。
SELECT
CONCAT('ALTER TABLE ', TABLE_SCHEMA,'.', TABLE_NAME,' MODIFY ', COLUMN_NAME,' VARBINARY;'),
CONCAT('ALTER TABLE ', TABLE_SCHEMA,'.', TABLE_NAME,' MODIFY ', COLUMN_NAME,' ', COLUMN_TYPE,' CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;')
FROM information_schema.columns
WHERE TABLE_SCHEMA IN ('[TABLE_SCHEMA]')
AND COLUMN_TYPE LIKE 'varchar%'
AND (COLLATION_NAME IS NOT NULL AND COLLATION_NAME NOT LIKE 'utf%');
<?php
/**
* Requires php >= 5.5
*
* Use this script to convert utf-8 data in utf-8 mysql tables stored via latin1 connection
* This is a PHP port from: https://gist.github.com/njvack/6113127
*
* BACKUP YOUR DATABASE BEFORE YOU RUN THIS SCRIPT!
*
* Once the script ran over your databases, change your database connection charset to utf8:
*
* $dsn = 'mysql:host=localhost;port=3306;charset=utf8';
*
* DON'T RUN THIS SCRIPT MORE THAN ONCE!
*
* @author hollodotme
*
* @author derclops since 2019-07-01
*
* I have taken the liberty to adapt this script to also do the following:
*
* - convert the database to utf8mb4
* - convert all tables to utf8mb4
* - actually then also convert the data to utf8mb4
*
*/
header('Content-Type: text/plain; charset=utf-8');
$dsn = 'mysql:host=localhost;port=3306;charset=utf8';
$user = 'root';
$password = 'root';
$options = [
\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY,
\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
\PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET latin1",
];
$dbManager = new \PDO( $dsn, $user, $password, $options );
$databasesToConvert = [ 'database1',/** database3, ... */ ];
$typesToConvert = [ 'char', 'varchar', 'tinytext', 'mediumtext', 'text', 'longtext' ];
foreach ( $databasesToConvert as $database )
{
echo $database, ":\n";
echo str_repeat( '=', strlen( $database ) + 1 ), "\n";
$dbManager->exec( "USE `{$database}`" );
echo "converting database to correct locale too ... \n";
$dbManager->exec("ALTER DATABASE `{$database}` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci");
$tablesStatement = $dbManager->query( "SHOW TABLES" );
while ( ($table = $tablesStatement->fetchColumn()) )
{
echo "Table: {$table}:\n";
echo str_repeat( '-', strlen( $table ) + 8 ), "\n";
$columnsToConvert = [ ];
$columsStatement = $dbManager->query( "DESCRIBE `{$table}`" );
while ( ($tableInfo = $columsStatement->fetch( \PDO::FETCH_ASSOC )) )
{
$column = $tableInfo['Field'];
echo ' * ' . $column . ': ' . $tableInfo['Type'];
$type = preg_replace( "#\(\d+\)#", '', $tableInfo['Type'] );
if ( in_array( $type, $typesToConvert ) )
{
echo " => must be converted\n";
$columnsToConvert[] = $column;
}
else
{
echo " => not relevant\n";
}
}
//convert table also!!!
$convert = "ALTER TABLE `{$table}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
echo "\n", $convert, "\n";
$dbManager->exec( $convert );
$databaseErrors = $dbManager->errorInfo();
if( !empty($databaseErrors[1]) ){
echo "\n !!!!!!!!!!!!!!!!! ERROR OCCURED ".print_r($databaseErrors, true)." \n";
exit;
}
if ( !empty($columnsToConvert) )
{
$converts = array_map(
function ( $column )
{
//return "`{$column}` = IFNULL(CONVERT(CAST(CONVERT(`{$column}` USING latin1) AS binary) USING utf8mb4),`{$column}`)";
return "`{$column}` = CONVERT(BINARY(CONVERT(`{$column}` USING latin1)) USING utf8mb4)";
},
$columnsToConvert
);
$query = "UPDATE IGNORE `{$table}` SET " . join( ', ', $converts );
//alternative
// UPDATE feedback SET reply = CONVERT(BINARY(CONVERT(reply USING latin1)) USING utf8mb4) WHERE feedback_id = 15015;
echo "\n", $query, "\n";
$dbManager->exec( $query );
$databaseErrors = $dbManager->errorInfo();
if( !empty($databaseErrors[1]) ){
echo "\n !!!!!!!!!!!!!!!!! ERROR OCCURED ".print_r($databaseErrors, true)." \n";
exit;
}
}
echo "\n--\n";
}
echo "\n";
}
mysql -uroot -pThatrootPassWord < alterTables.sql
機能します。そして、すでに述べたように、utf8mb4_binは、とりわけnextcloudが推奨するものです。