it-swarm.dev

Um script para alterar todas as tabelas e campos para o agrupamento utf-8-bin no MYSQL

Existe um script SQL ou PHP que eu possa executar para alterar o agrupamento padrão em todas as tabelas e campos de um banco de dados?

Eu mesmo posso escrever um, mas acho que isso deve ser algo prontamente disponível em um site como esse. Se eu puder me apresentar antes de alguém postar um, eu mesmo postarei.

55
nlaq

Seja cuidadoso! Se você realmente tiver utf armazenado como outra codificação, você pode ter uma verdadeira bagunça em suas mãos. Faça o backup primeiro. Em seguida, tente alguns dos métodos padrão:

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

Eu tive que recorrer a converter todos os campos de texto para binário, em seguida, de volta para varchar/text. Isso salvou minha bunda. 

Eu tinha dados é UTF8, armazenado como latin1. O que eu fiz:

Elimine índices. Converta campos em binário. Converta em utf8-general ci

Se o seu no LAMP, não se esqueça de adicionar o comando set NAMES antes de interagir com o banco de dados, e certifique-se de definir os cabeçalhos de codificação de caracteres. 

24
Buzz

Pode ser feito em um único comando (ao invés de 148 do 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 &

Você precisa amar a linha de comando ... (Talvez seja necessário empregar as opções --user e --password para mysql).

EDIT: para evitar problemas de chave estrangeira, adicionado SET foreign_key_checks = 0; e SET foreign_key_checks = 1;

85
DavidWinterbottom

Eu acho que é fácil fazer isso em duas etapas rodando no PhpMyAdmin.
Passo 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

Passo 2:
Esta consulta gerará uma lista de consultas, uma para cada tabela. Você precisa copiar a lista de consultas e colá-las na linha de comando ou na guia SQL do PhpMyAdmin para que as alterações sejam feitas.

39
Ivan

Este snippet PHP irá alterar o agrupamento em todas as tabelas em um banco de dados. (É tirado de este 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 />";
    }
}
?> 
14
Rich Adams

Outra abordagem usando a linha de comando, baseada em @ david sem a 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

embelezado

  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
4
RameshVel

Uma versão mais completa do script acima pode ser encontrada aqui:

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

Por favor, deixe algum comentário sobre esta contribuição aqui: http://www.zen-cart.com/forum/showthread.php?p=1034214

3
Dustin

Em scripts acima de todas as tabelas selecionadas para conversão (com SHOW TABLES), mas uma maneira mais conveniente e portátil de verificar o agrupamento de tabelas antes de converter uma tabela. Essa consulta faz isso:

SELECT table_name
     , table_collation 
FROM information_schema.tables
1
Alexander I.Grafov

Charset e collation não são a mesma coisa. Um agrupamento é um conjunto de regras sobre como classificar seqüências de caracteres. Um charset é um conjunto de regras sobre como representar caracteres. Um agrupamento depende do conjunto de caracteres.

1
troelskn

Use meu shell personalizado collatedb , deve funcionar: 

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

Exemplo:

collatedb root 0000 myDatabase utf8_bin
0
Abdennour TOUMI

Eu atualizei a resposta do nlaq para trabalhar com PHP7 e para manipular corretamente índices de várias colunas, dados binários ordenados (por exemplo, latin1_bin), etc., e limpar o código um pouco. Este é o único código que eu encontrei/tentei que migrei com sucesso meu banco de dados de latin1 para 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>";

?>
0
davewy

Para usuários do Windows

Além de @davidwinterbottom answer, Usuários do Windows podem usar o comando abaixo:

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] &

Substitua placeholders [database], [user] e [password] por valores reais.

Git-bash os usuários podem baixar este bash script e executá-lo facilmente.

0
Lost Koder

Eu acho que o caminho mais rápido é com o phpmyadmin e alguns jQuery no console.

Vá para a estrutura da tabela e abra o console do desenvolvedor chrome/firefox (normalmente F12 no teclado):

  1. execute este código para selecionar todos os campos com charset incorreto e iniciar a modificação:

    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. quando a página é carregada, use este código no console para selecionar a codificação correta:

    $("select[name*='field_collation']" ).val('utf8_general_ci');
    
  3. salve 

  4. alterar o conjunto de caracteres da tabela no campo "Agrupamento" na guia "Operação"

Testado no phpmyadmin 4.0 e 4.4, mas acho que funciona em todas as versões 4.x

0
Luca Camillo

Aqui está uma maneira fácil de fazer isso com apenas phpmyadmin se você não tiver acesso à linha de comando ou acesso para editar INFORMATION_SCHEMA.

Primeiro, ouça o conselho de muitas das outras respostas aqui - você pode realmente estragar as coisas aqui, então faça um backup. Agora faça um backup do seu backup. Também é improvável que isso funcione se os dados forem codificados de maneira diferente daquela para a qual você está alterando.

Observe que você precisará localizar os nomes exatos do esquema incorreto e a codificação de caracteres dos quais você precisa mudar antes de iniciar.

  1. Exportar o banco de dados como SQL; Faça uma cópia; Abra em um editor de texto de sua escolha
  2. Encontre e Substitua o esquema primeiro, por exemplo - find: latin1_swedish_ci , replace: utf8_general_ci
  3. Encontre e Substitua as codificações de caracteres se você precisar, por exemplo - encontrar: latin1 , replace: utf8
  4. Crie um novo banco de dados de teste e carregue seu novo arquivo SQL no phpmyadmin

Essa é uma maneira super fácil de fazer isso, mas, novamente, isso não alterará a codificação de seus dados, portanto, funcionará apenas em determinadas circunstâncias.

0
squarecandy

Obrigado @nlaq pelo código, que me iniciou na solução abaixo.

Eu lancei um plugin para WordPress sem perceber que o WordPress não define o agrupamento automaticamente. Então, muitas pessoas usando o plugin acabaram com latin1_swedish_ci quando deveria ter sido utf8_general_ci.

Aqui está o código que adicionei ao plug-in para detectar o agrupamento latin1_swedish_ci e alterá-lo para utf8_general_ci.

Teste este código antes de usá-lo em seu próprio plugin!

// 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();
0
dtbaker

Uma solução simples (burra?), Usando o recurso de seleção múltipla do Your IDE: 

  1. execute "SHOW TABLES;" coluna de resultados de consulta e cópia (nomes de tabelas).
  2. selecione vários começos e adicione "ALTER TABLE".
  3. final de multi-select e adicione "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;"
  4. executar consultas criadas.
0
snp0k