57 votes

Un script pour changer toutes les tables et champs à la collation utf-8-bin dans MYSQL

Y a-t-il un SQL o PHP script que je peux exécuter pour changer la collation par défaut dans toutes les tables et champs d'une base de données ?

Je peux en écrire un moi-même, mais je pense que cela devrait être quelque chose de facilement disponible sur un site comme celui-ci. Si je peux en trouver un moi-même avant que quelqu'un en poste un, je le posterai moi-même.

0 votes

86voto

DavidWinterbottom Points 2632

Peut être fait en une seule commande (plutôt que 148 de 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 &

Vous devez aimer la ligne de commande... (Vous pourriez avoir besoin d'employer la --user et --password options pour mysql ).

EDIT : pour éviter les problèmes de clés étrangères, j'ai ajouté SET foreign_key_checks = 0; et SET foreign_key_checks = 1;

0 votes

Super, ça a marché pour moi... quelques problèmes avec les encodages de caractères avec les valeurs sur les champs, heureusement ma base de données est petite pour le moment

0 votes

@david Cela fonctionne très bien, mais est-il possible d'enregistrer la requête en ligne de commande ou simplement de notifier la fin du processus de traitement par lots. Actuellement, lorsque je l'exécute, il démarre un processus en arrière-plan et je ne sais pas quand il se termine. J'ai essayé de mettre echo dans awk, mais rien ne fonctionne.

0 votes

Lorsque j'utilise cette commande, je n'obtiens aucune réponse. L'invite est simplement "suspendue". Je ne suis pas sûr qu'elle ait été exécutée, correctement ou pas du tout.

41voto

Ivan Points 181

Je pense qu'il est facile de faire cela en deux étapes en utilisant PhpMyAdmin.
Étape 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

Étape 2 :
Cette requête produira une liste de requêtes, une pour chaque table. Vous devez copier la liste des requêtes, et les coller dans la ligne de commande ou dans l'onglet SQL de PhpMyAdmin pour que les changements soient effectués.

0 votes

Veuillez fournir des liens vers des sites en langue anglaise ou mieux, fournir une réponse complète et n'utiliser les liens qu'à titre de référence !

0 votes

Notez que cette requête n'apportera aucune modification à votre base de données. Elle produira une liste de requêtes - une pour chaque table. Vous devez donc COPIER la liste des requêtes et la COLLER dans la ligne de commande ou dans l'onglet SQL de PHPMyAdmin pour que les changements soient effectués.

0 votes

Fonctionne parfaitement ! Merci, c'est une façon très intelligente et astucieuse d'effectuer un changement de collation par lot avec seulement mysql ou phpMyAdmin. C'est très utile dans l'installation de redmine, où la collation par défaut est latin1 au lieu de utf8.

27voto

nlaq Points 11379

OK, j'ai écrit ceci en tenant compte de ce qui a été dit dans ce fil. Merci pour l'aide, et j'espère que ce script aidera d'autres personnes. Je n'ai aucune garantie pour son utilisation, alors VEUILLEZ FAIRE UNE SAUVEGARDE avant de l'exécuter. Il s'agit de debe fonctionne avec toutes les bases de données ; et il a très bien fonctionné sur ma propre base.

EDIT : Ajout de paramètres en haut de la page pour le jeu de caractères et le collatéral à convertir. EDIT2 : Change le jeu de caractères/collatéral par défaut de la base de données et des tables.

<?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>";

?>

0 votes

Oui, jusqu'ici tout va bien. Je l'ai appliqué un par un à mes bases de données et jusqu'à présent aucune perte de données.

4 votes

Attention : En regardant le code source, il me semble que ce script ne recrée pas les index uniques multicolonnes, il les supprime simplement.

0 votes

Excellent article ! Quelqu'un a-t-il modifié ce script pour gérer les "index uniques multicolonnes" ? Si oui, veuillez poster ou m'envoyer un courriel à gmail - jjwdesign. Merci, Jeff

23voto

Buzz Points 1088

Faites attention ! Si vous avez stocké utf comme un autre encodage, vous pourriez avoir un vrai problème sur les bras. Faites d'abord une sauvegarde. Ensuite, essayez certaines des méthodes standard :

par exemple http://www.cesspit.net/drupal/node/898 http://www.hackszine.com/blog/archive/2007/05/mysql_database_migration_latin.html

J'ai dû recourir à la conversion de tous les champs de texte en binaire, puis à nouveau en varchar/texte. Ceci m'a sauvé la mise.

J'avais des données en UTF8, stockées en latin1. Ce que j'ai fait :

Suppression des index. Convertir les champs en binaire. Convertir en utf8-general ci

Si vous utilisez LAMP, n'oubliez pas d'ajouter la commande set NAMES avant d'interagir avec la base de données, et assurez-vous de définir les en-têtes de codage des caractères.

13voto

Rich Adams Points 10378

Cet extrait PHP va changer la collation sur toutes les tables d'une base de données. (Il est tiré de ce site .)

<?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 />";
    }
}
?>

0 votes

Après l'avoir exécuté sur ma base de données, lorsque j'essaie de voir la structure de toutes mes tables, je vois.. : #126 - Fichier clé incorrect pour la table '/tmp/#sql_321_0.MYI' ; essayez de le réparer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X