Скрипт для изменения всех таблиц и полей на сортировку utf-8-bin в MYSQL

Есть ли сценарий SQL или PHP, который я могу запустить, который изменит параметры сортировки по умолчанию во всех таблицах и полях в базе данных?

Я могу написать его сам, но я думаю, что это должно быть что-то, что должно быть легко доступно на подобном сайте. Если я сам смогу придумать что-нибудь, прежде чем кто-нибудь опубликует его, я опубликую его сам.


person Community    schedule 19.09.2008    source источник


Ответы (17)


Будь осторожен! Если у вас действительно есть utf, сохраненный как другая кодировка, у вас может быть настоящий беспорядок. Сначала сделайте резервную копию. Тогда попробуйте некоторые из стандартных методов:

например, http://www.cesspit.net/drupal/node/898 http://www.hackszine.com/blog/archive/2007/05/mysql_database_migration_latin.html

Мне пришлось преобразовать все текстовые поля в двоичные, а затем обратно в varchar / text. Это спасло мою задницу.

У меня были данные UTF8, хранящиеся как latin1. Что я сделал:

Отбросьте индексы. Преобразуйте поля в двоичные. Преобразовать в utf8-general ci

Если вы используете LAMP, не забудьте добавить команду set NAMES перед взаимодействием с базой данных и убедитесь, что вы установили заголовки кодировки символов.

person Buzz    schedule 19.09.2008

Можно сделать одной командой (а не 148 в PHP):

mysql --database=dbname -B -N -e "SHOW TABLES" \
| awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' \
| mysql --database=dbname &

Вы должны полюбить командную строку ... (Возможно, вам придется использовать параметры --user и --password для mysql).

РЕДАКТИРОВАТЬ: чтобы избежать проблем с внешним ключом, добавлены SET foreign_key_checks = 0; и SET foreign_key_checks = 1;

person DavidWinterbottom    schedule 21.03.2009
comment
отлично, это сработало для меня ... некоторая проблема с кодировками символов со значениями в полях, к счастью, мой db пока мал - person arod; 01.09.2012
comment
@david Отлично работает, но можно ли регистрировать запрос в командной строке или просто уведомлять о завершении пакетного процесса. в настоящее время, когда я запускаю это, он запускает фоновый процесс, и я не уверен, когда он закончится. Я пробовал поместить эхо в awk, но ничего не работает - person RameshVel; 18.04.2013
comment
Когда я использую эту команду, я не получаю никакого ответа. Подсказка просто зависает. Не уверен, действительно ли он выполнен, правильно или вообще - person Marc; 26.04.2013
comment
@DavidWinterbottom для этого ответа вам следует установить статую в вашу честь в вашем родном городе. - person NotGaeL; 24.05.2013
comment
Вы должны знать, что такой подход может вызвать проблемы. Во-первых, после запуска все столбцы latin1, которые были ТЕКСТОМ, теперь будут СРЕДНИЙ ТЕКСТ. В результате у вас может быть тихая потеря / усечение данных. См .: codex.wordpress.org/Converting_Database_Character_Sets и mysqlperformanceblog.com/2009/03/17/converting-character-sets для получения более подробной информации. - person alexleonard; 23.01.2014
comment
это приведет к ошибке, если у вас есть представления в вашей базе данных. чтобы исключить просмотры, замените "SHOW TABLES" на "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'". Требуется MySQL 5.0.2 или выше. - person chadrik; 21.05.2014
comment
Точный код командной строки, на который я получаю ответ: mysql -u root -ppassword --database=dbname -B -N -e "SHOW TABLES" | awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' | mysql -u root -ppassword --database=dbname & - person shgnInc; 07.07.2014
comment
Чтобы не возвращать представление, я адаптирую эту команду следующим образом: mysql -proot --database=dbname -B -N -e "SELECT TABLE_NAME FROM information_schema.tables where TABLE_TYPE = 'BASE TABLE' and TABLE_SCHEMA = 'schemaname'" | awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' | mysql -proot --database=dbname - person blobmaster; 11.12.2020

Я думаю, что это легко сделать в два шага с помощью PhpMyAdmin.
Шаг 1:

SELECT CONCAT('ALTER TABLE `', t.`TABLE_SCHEMA`, '`.`', t.`TABLE_NAME`,
 '` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') as stmt 
FROM `information_schema`.`TABLES` t
WHERE 1
AND t.`TABLE_SCHEMA` = 'database_name'
ORDER BY 1

Шаг 2:
Этот запрос выведет список запросов, по одному для каждой таблицы. Вам нужно скопировать список запросов и вставить их в командную строку или на вкладку SQL PhpMyAdmin, чтобы внести изменения.

person Ivan    schedule 22.06.2010
comment
дайте ссылки на сайты на английском языке или лучше, дайте полный ответ и используйте ссылки только в качестве справочных! - person sra; 05.01.2012
comment
Обратите внимание, что этот запрос НЕ внесет никаких изменений в вашу БД. Он выведет список запросов - по одному для каждой таблицы. Поэтому вам нужно КОПИРОВАТЬ список запросов и ВСТАВИТЬ их в командную строку или на вкладку SQL PHPMyAdmin для внесения изменений. - person Costa; 06.03.2013
comment
Отлично работает! Спасибо, это очень умный и хитрый способ выполнить пакетное изменение параметров сортировки только с помощью mysql или phpMyAdmin. Это очень полезно при установке Redmine, где по умолчанию используется сортировка latin1 вместо utf8. - person 18augst; 23.09.2014

Хорошо, я написал это с учетом сказанного в этой ветке. Спасибо за помощь, и я надеюсь, что этот сценарий поможет другим. У меня нет никаких гарантий на его использование, поэтому ПОЖАЛУЙСТА, РЕЗЕРВНОЕ КОПИРОВАНИЕ перед запуском. Он должен работать со всеми базами данных; и он отлично работал сам.

РЕДАКТИРОВАТЬ: добавлены переменные вверху, для которых нужно преобразовать кодировку / сопоставление. EDIT2: изменяет кодировку / сопоставление по умолчанию для базы данных и таблиц

<?php

function MysqlError()
{
    if (mysql_errno())
    {
        echo "<b>Mysql Error: " . mysql_error() . "</b>\n";
    }
}

$username = "root";
$password = "";
$db = "database";
$host = "localhost";

$target_charset = "utf8";
$target_collate = "utf8_general_ci";

echo "<pre>";

$conn = mysql_connect($host, $username, $password);
mysql_select_db($db, $conn);

$tabs = array();
$res = mysql_query("SHOW TABLES");
MysqlError();
while (($row = mysql_fetch_row($res)) != null)
{
    $tabs[] = $row[0];
}

// now, fix tables
foreach ($tabs as $tab)
{
    $res = mysql_query("show index from {$tab}");
    MysqlError();
    $indicies = array();

    while (($row = mysql_fetch_array($res)) != null)
    {
        if ($row[2] != "PRIMARY")
        {
            $indicies[] = array("name" => $row[2], "unique" => !($row[1] == "1"), "col" => $row[4]);
            mysql_query("ALTER TABLE {$tab} DROP INDEX {$row[2]}");
            MysqlError();
            echo "Dropped index {$row[2]}. Unique: {$row[1]}\n";
        }
    }

    $res = mysql_query("DESCRIBE {$tab}");
    MysqlError();
    while (($row = mysql_fetch_array($res)) != null)
    {
        $name = $row[0];
        $type = $row[1];
        $set = false;
        if (preg_match("/^varchar\((\d+)\)$/i", $type, $mat))
        {
            $size = $mat[1];
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} VARBINARY({$size})");
            MysqlError();
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} VARCHAR({$size}) CHARACTER SET {$target_charset}");
            MysqlError();
            $set = true;

            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }
        else if (!strcasecmp($type, "CHAR"))
        {
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} BINARY(1)");
            MysqlError();
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} VARCHAR(1) CHARACTER SET {$target_charset}");
            MysqlError();
            $set = true;

            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }
        else if (!strcasecmp($type, "TINYTEXT"))
        {
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} TINYBLOB");
            MysqlError();
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} TINYTEXT CHARACTER SET {$target_charset}");
            MysqlError();
            $set = true;

            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }
        else if (!strcasecmp($type, "MEDIUMTEXT"))
        {
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} MEDIUMBLOB");
            MysqlError();
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} MEDIUMTEXT CHARACTER SET {$target_charset}");
            MysqlError();
            $set = true;

            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }
        else if (!strcasecmp($type, "LONGTEXT"))
        {
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} LONGBLOB");
            MysqlError();
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} LONGTEXT CHARACTER SET {$target_charset}");
            MysqlError();
            $set = true;

            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }
        else if (!strcasecmp($type, "TEXT"))
        {
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} BLOB");
            MysqlError();
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} TEXT CHARACTER SET {$target_charset}");
            MysqlError();
            $set = true;

            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }

        if ($set)
            mysql_query("ALTER TABLE {$tab} MODIFY {$name} COLLATE {$target_collate}");
    }

    // re-build indicies..
    foreach ($indicies as $index)
    {
        if ($index["unique"])
        {
            mysql_query("CREATE UNIQUE INDEX {$index["name"]} ON {$tab} ({$index["col"]})");
            MysqlError();
        }
        else
        {
            mysql_query("CREATE INDEX {$index["name"]} ON {$tab} ({$index["col"]})");
            MysqlError();
        }

        echo "Created index {$index["name"]} on {$tab}. Unique: {$index["unique"]}\n";
    }

    // set default collate
    mysql_query("ALTER TABLE {$tab}  DEFAULT CHARACTER SET {$target_charset} COLLATE {$target_collate}");
}

// set database charset
mysql_query("ALTER DATABASE {$db} DEFAULT CHARACTER SET {$target_charset} COLLATE {$target_collate}");

mysql_close($conn);
echo "</pre>";

?>
person Community    schedule 19.09.2008
comment
Ага; Все идет нормально. Я применял его один за другим к своим базам данных и до сих пор без потери данных. - person ; 07.10.2008
comment
Внимание: глядя на исходный код, мне кажется, что этот скрипт не воссоздает многоколоночные уникальные индексы, а просто отбрасывает их. - person knb; 11.01.2011
comment
Отличный пост! Кто-нибудь изменил этот скрипт для обработки уникальных индексов с несколькими столбцами? Так, пожалуйста, напишите мне на gmail - jjwdesign. Спасибо Джефф - person jjwdesign; 29.01.2012
comment
Единственная проблема в том, что он отбрасывает весь ваш многоколоночный индекс. По крайней мере, он показывает журнал, позволяющий узнать, какие из них были сброшены! - person Farzher; 24.07.2012
comment
Очень полезная отправная точка! Мой ответ обновляет это, чтобы обрабатывать индексы с несколькими столбцами, двоичные сопоставления и т. Д., И немного очищен. - person davewy; 02.03.2017

Этот фрагмент PHP изменит параметры сортировки для всех таблиц в базе данных. (Это взято с этого сайта.)

<?php
// your connection
mysql_connect("localhost","root","***");
mysql_select_db("db1");

// convert code
$res = mysql_query("SHOW TABLES");
while ($row = mysql_fetch_array($res))
{
    foreach ($row as $key => $table)
    {
        mysql_query("ALTER TABLE " . $table . " CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci");
        echo $key . " =&gt; " . $table . " CONVERTED<br />";
    }
}
?> 
person Rich Adams    schedule 19.09.2008
comment
Когда я запускаю его на своей базе данных, когда я пытаюсь увидеть структуру каждой моей таблицы, я вижу: # 126 - Неверный ключевой файл для таблицы '/tmp/#sql_321_0.MYI'; попробуй отремонтировать это - person YankeeWhiskey; 28.03.2013

Другой подход с использованием командной строки, основанный на @ david без awk

for t in $(mysql --user=root --password=admin  --database=DBNAME -e "show tables";);do echo "Altering" $t;mysql --user=root --password=admin --database=DBNAME -e "ALTER TABLE $t CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;";done

украшенный

  for t in $(mysql --user=root --password=admin  --database=DBNAME -e "show tables";);
    do 
       echo "Altering" $t;
       mysql --user=root --password=admin --database=DBNAME -e "ALTER TABLE $t CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;";
    done
person RameshVel    schedule 18.04.2013
comment
Вы должны добавить --silent к первой mysql команде, чтобы избежать ошибки для первой строки, которая равна Tables_in_xxx. Кроме того, экранирование имен таблиц позволит избежать ошибки для таблиц, использующих зарезервированное имя (например, Order). - person BenMorel; 25.09.2013

Более полную версию приведенного выше сценария можно найти здесь:

http://www.zen-cart.com/index.php?main_page=product_contrib_info&products_id=1937

Оставляйте отзывы об этом вкладе здесь: http://www.zen-cart.com/forum/showthread.php?p=1034214

person Dustin    schedule 03.06.2011
comment
Спасибо, Дастин! Скрипт Zen-Cart (версия) - это именно то, что я искал. Он правильно обрабатывает многопольный индекс / уникальные индексы. Замечательно, это экономит мне много времени и сил. - person jjwdesign; 29.01.2012
comment
Пример №1 того, почему ответы только по ссылкам плохие. - person MECU; 10.04.2018

Кодировка и сопоставление - это не одно и то же. Параметры сортировки - это набор правил сортировки строк. Кодировка - это набор правил о том, как представлять символы. Сопоставление зависит от кодировки.

person troelskn    schedule 19.09.2008

В сценариях выше все таблицы, выбранные для преобразования (с SHOW TABLES), но более удобный и переносимый способ проверки сопоставления таблиц перед преобразованием таблицы. Этот запрос делает это:

SELECT table_name
     , table_collation 
FROM information_schema.tables
person Alexander I.Grafov    schedule 03.06.2012

Используйте мою настраиваемую оболочку collatedb, она должна работать:

collatedb <username> <password> <database> <collation>

Пример :

collatedb root 0000 myDatabase utf8_bin
person Abdennour TOUMI    schedule 11.10.2013

Спасибо @nlaq за код, с которого я начал работу над решением ниже.

Я выпустил плагин WordPress, не осознавая, что WordPress не устанавливает подборку автоматически. Таким образом, многие люди, использующие плагин, получили latin1_swedish_ci, хотя должно было быть utf8_general_ci.

Вот код, который я добавил в плагин, чтобы обнаружить latin1_swedish_ci сопоставление и изменить его на utf8_general_ci.

Протестируйте этот код, прежде чем использовать его в своем собственном плагине!

// list the names of your wordpress plugin database tables (without db prefix)
$tables_to_check = array(
    'social_message',
    'social_facebook',
    'social_facebook_message',
    'social_facebook_page',
    'social_google',
    'social_google_mesage',
    'social_twitter',
    'social_twitter_message',
);
// choose the collate to search for and replace:
$convert_fields_collate_from = 'latin1_swedish_ci';
$convert_fields_collate_to = 'utf8_general_ci';
$convert_tables_character_set_to = 'utf8';
$show_debug_messages = false;
global $wpdb;
$wpdb->show_errors();
foreach($tables_to_check as $table) {
    $table = $wpdb->prefix . $table;
    $indicies = $wpdb->get_results(  "SHOW INDEX FROM `$table`", ARRAY_A );
    $results = $wpdb->get_results( "SHOW FULL COLUMNS FROM `$table`" , ARRAY_A );
    foreach($results as $result){
        if($show_debug_messages)echo "Checking field ".$result['Field'] ." with collat: ".$result['Collation']."\n";
        if(isset($result['Field']) && $result['Field'] && isset($result['Collation']) && $result['Collation'] == $convert_fields_collate_from){
            if($show_debug_messages)echo "Table: $table - Converting field " .$result['Field'] ." - " .$result['Type']." - from $convert_fields_collate_from to $convert_fields_collate_to \n";
            // found a field to convert. check if there's an index on this field.
            // we have to remove index before converting field to binary.
            $is_there_an_index = false;
            foreach($indicies as $index){
                if ( isset($index['Column_name']) && $index['Column_name'] == $result['Field']){
                    // there's an index on this column! store it for adding later on.
                    $is_there_an_index = $index;
                    $wpdb->query( $wpdb->prepare( "ALTER TABLE `%s` DROP INDEX %s", $table, $index['Key_name']) );
                    if($show_debug_messages)echo "Dropped index ".$index['Key_name']." before converting field.. \n";
                    break;
                }
            }
            $set = false;

            if ( preg_match( "/^varchar\((\d+)\)$/i", $result['Type'], $mat ) ) {
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` VARBINARY({$mat[1]})" );
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` VARCHAR({$mat[1]}) CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
                $set = true;
            } else if ( !strcasecmp( $result['Type'], "CHAR" ) ) {
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` BINARY(1)" );
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` VARCHAR(1) CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
                $set = true;
            } else if ( !strcasecmp( $result['Type'], "TINYTEXT" ) ) {
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` TINYBLOB" );
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` TINYTEXT CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
                $set = true;
            } else if ( !strcasecmp( $result['Type'], "MEDIUMTEXT" ) ) {
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` MEDIUMBLOB" );
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` MEDIUMTEXT CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
                $set = true;
            } else if ( !strcasecmp( $result['Type'], "LONGTEXT" ) ) {
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` LONGBLOB" );
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` LONGTEXT CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
                $set = true;
            } else if ( !strcasecmp( $result['Type'], "TEXT" ) ) {
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` BLOB" );
                $wpdb->query( "ALTER TABLE `{$table}` MODIFY `{$result['Field']}` TEXT CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
                $set = true;
            }else{
                if($show_debug_messages)echo "Failed to change field - unsupported type: ".$result['Type']."\n";
            }
            if($set){
                if($show_debug_messages)echo "Altered field success! \n";
                $wpdb->query( "ALTER TABLE `$table` MODIFY {$result['Field']} COLLATE $convert_fields_collate_to" );
            }
            if($is_there_an_index !== false){
                // add the index back.
                if ( !$is_there_an_index["Non_unique"] ) {
                    $wpdb->query( "CREATE UNIQUE INDEX `{$is_there_an_index['Key_name']}` ON `{$table}` ({$is_there_an_index['Column_name']})", $is_there_an_index['Key_name'], $table, $is_there_an_index['Column_name'] );
                } else {
                    $wpdb->query( "CREATE UNIQUE INDEX `{$is_there_an_index['Key_name']}` ON `{$table}` ({$is_there_an_index['Column_name']})", $is_there_an_index['Key_name'], $table, $is_there_an_index['Column_name'] );
                }
            }
        }
    }
    // set default collate
    $wpdb->query( "ALTER TABLE `{$table}` DEFAULT CHARACTER SET {$convert_tables_character_set_to} COLLATE {$convert_fields_collate_to}" );
    if($show_debug_messages)echo "Finished with table $table \n";
}
$wpdb->hide_errors();
person dtbaker    schedule 17.06.2014

Простое (глупое? :) решение, использующее функцию множественного выбора вашей IDE:

  1. запустите "ПОКАЗАТЬ ТАБЛИЦЫ;" столбец результатов запроса и копирования (названия таблиц).
  2. выберите несколько начал и добавьте «ИЗМЕНИТЬ ТАБЛИЦУ».
  3. выберите несколько окончаний и добавьте «ПРЕОБРАЗОВАТЬ В НАБОР СИМВОЛОВ utf8 COLLATE utf8_general_ci;»
  4. запускать созданные запросы.
person snp0k    schedule 07.07.2015

Вот простой способ сделать это с помощью phpmyadmin, если у вас нет доступа к командной строке или доступа для редактирования INFORMATION_SCHEMA.

Во-первых, прислушайтесь к советам многих других ответов здесь - здесь вы действительно можете напортачить, поэтому сделайте резервную копию. Теперь сделайте резервную копию вашей резервной копии. Кроме того, это вряд ли сработает, если ваши данные закодированы не так, как вы их меняете.

Обратите внимание, что вам нужно будет найти точные имена нарушающей схемы и кодировки символов, которые вам нужно изменить перед запуском.

  1. Экспорт базы данных как SQL; Сделать копию; Откройте его в любом текстовом редакторе.
  2. Сначала найдите и замените схему - найдите: latin1_swedish_ci, замените: utf8_general_ci
  3. Найдите и замените кодировки символов, если вам нужно, например, найдите: latin1, замените: utf8
  4. Создайте новую тестовую базу данных и загрузите новый файл SQL в phpmyadmin.

Это очень простой способ сделать это, но опять же, это не изменит кодировку ваших данных, поэтому он будет работать только в определенных обстоятельствах.

person squarecandy    schedule 06.02.2016

Я думаю, что самый быстрый способ - использовать phpmyadmin и некоторый jQuery на консоли.

Перейдите к структуре таблицы и откройте консоль разработчика chrome / firefox (обычно F12 на клавиатуре):

  1. запустите этот код, чтобы выбрать все поля с неправильной кодировкой и начать изменение:

    var elems = $('dfn'); var lastID = elems.length - 1;
    elems.each(function(i) {
        if ($(this).html() != 'utf8_general_ci') { 
           $('input:checkbox', $('td', $(this).parent().parent()).first()).attr('checked','checked');
        }       
    
        if (i == lastID) {
            $("button[name='submit_mult'][value='change']").click();
        }
    });
    
  2. когда страница загружена, используйте этот код на консоли для выбора правильной кодировки:

    $("select[name*='field_collation']" ).val('utf8_general_ci');
    
  3. спасти

  4. изменить кодировку таблицы в поле «Сортировка» на вкладке «Операция»

Проверено на phpmyadmin 4.0 и 4.4, но думаю работает на всех версиях 4.x

person Luca Camillo    schedule 03.11.2015

Я обновил ответ nlaq для работы с PHP7 и для правильной обработки многоколоночных индексов, двоичных сопоставленных данных (например, latin1_bin) и т.д., а также немного очистил код. Это единственный код, который я нашел / попробовал, который успешно перенес мою базу данных с latin1 на utf8.

<?php

/////////// BEGIN CONFIG ////////////////////

$username = "";
$password = "";
$db = "";
$host = "";

$target_charset = "utf8";
$target_collation = "utf8_unicode_ci";
$target_bin_collation = "utf8_bin";

///////////  END CONFIG  ////////////////////

function MySQLSafeQuery($conn, $query) {
    $res = mysqli_query($conn, $query);
    if (mysqli_errno($conn)) {
        echo "<b>Mysql Error: " . mysqli_error($conn) . "</b>\n";
        echo "<span>This query caused the above error: <i>" . $query . "</i></span>\n";
    }
    return $res;
}

function binary_typename($type) {
    $mysql_type_to_binary_type_map = array(
        "VARCHAR" => "VARBINARY",
        "CHAR" => "BINARY(1)",
        "TINYTEXT" => "TINYBLOB",
        "MEDIUMTEXT" => "MEDIUMBLOB",
        "LONGTEXT" => "LONGBLOB",
        "TEXT" => "BLOB"
    );

    $typename = "";
    if (preg_match("/^varchar\((\d+)\)$/i", $type, $mat))
        $typename = $mysql_type_to_binary_type_map["VARCHAR"] . "(" . (2*$mat[1]) . ")";
    else if (!strcasecmp($type, "CHAR"))
        $typename = $mysql_type_to_binary_type_map["CHAR"] . "(1)";
    else if (array_key_exists(strtoupper($type), $mysql_type_to_binary_type_map))
        $typename = $mysql_type_to_binary_type_map[strtoupper($type)];
    return $typename;
}

echo "<pre>";

// Connect to database
$conn = mysqli_connect($host, $username, $password);
mysqli_select_db($conn, $db);

// Get list of tables
$tabs = array();
$query = "SHOW TABLES";
$res = MySQLSafeQuery($conn, $query);
while (($row = mysqli_fetch_row($res)) != null)
    $tabs[] = $row[0];

// Now fix tables
foreach ($tabs as $tab) {
    $res = MySQLSafeQuery($conn, "SHOW INDEX FROM `{$tab}`");
    $indicies = array();

    while (($row = mysqli_fetch_array($res)) != null) {
        if ($row[2] != "PRIMARY") {
            $append = true;
            foreach ($indicies as $index) {
                if ($index["name"] == $row[2]) {
                    $index["col"][] = $row[4];
                    $append = false;
                }
            }
            if($append)
                $indicies[] = array("name" => $row[2], "unique" => !($row[1] == "1"), "col" => array($row[4]));
        }
    }

    foreach ($indicies as $index) {
        MySQLSafeQuery($conn, "ALTER TABLE `{$tab}` DROP INDEX `{$index["name"]}`");
        echo "Dropped index {$index["name"]}. Unique: {$index["unique"]}\n";
    }

    $res = MySQLSafeQuery($conn, "SHOW FULL COLUMNS FROM `{$tab}`");
    while (($row = mysqli_fetch_array($res)) != null) {
        $name = $row[0];
        $type = $row[1];
        $current_collation = $row[2];
        $target_collation_bak = $target_collation;
        if(!strcasecmp($current_collation, "latin1_bin"))
            $target_collation = $target_bin_collation;
        $set = false;
        $binary_typename = binary_typename($type);
        if ($binary_typename != "") {
            MySQLSafeQuery($conn, "ALTER TABLE `{$tab}` MODIFY `{$name}` {$binary_typename}");
            MySQLSafeQuery($conn, "ALTER TABLE `{$tab}` MODIFY `{$name}` {$type} CHARACTER SET '{$target_charset}' COLLATE '{$target_collation}'");
            $set = true;
            echo "Altered field {$name} on {$tab} from type {$type}\n";
        }
        $target_collation = $target_collation_bak;
    }

    // Rebuild indicies
    foreach ($indicies as $index) {
         // Handle multi-column indices
         $joined_col_str = "";
         foreach ($index["col"] as $col)
             $joined_col_str = $joined_col_str . ", `" . $col . "`";
         $joined_col_str = substr($joined_col_str, 2);

         $query = "";
         if ($index["unique"])
             $query = "CREATE UNIQUE INDEX `{$index["name"]}` ON `{$tab}` ({$joined_col_str})";
         else
             $query = "CREATE INDEX `{$index["name"]}` ON `{$tab}` ({$joined_col_str})";
         MySQLSafeQuery($conn, $query);

        echo "Created index {$index["name"]} on {$tab}. Unique: {$index["unique"]}\n";
    }

    // Set default character set and collation for table
    MySQLSafeQuery($conn, "ALTER TABLE `{$tab}`  DEFAULT CHARACTER SET '{$target_charset}' COLLATE '{$target_collation}'");
}

// Set default character set and collation for database
MySQLSafeQuery($conn, "ALTER DATABASE `{$db}` DEFAULT CHARACTER SET '{$target_charset}' COLLATE '{$target_collation}'");

mysqli_close($conn);
echo "</pre>";

?>
person davewy    schedule 02.03.2017

Для пользователей Windows

В дополнение к ответу @davidwinterbottom пользователи Windows могут использовать команду ниже:

mysql.exe --database=[database] -u [user] -p[password] -B -N -e "SHOW TABLES" \
| awk.exe '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' \
| mysql.exe -u [user] -p[password] --database=[database] &

Замените заполнители [база данных], [пользователь] и [пароль] фактическими значениями.

Пользователи Git-bash могут загрузить этот сценарий bash и легко его запустить. .

person Lost Koder    schedule 06.05.2017