在MYSQL中将所有表和字段更改为utf-8-bin排序规则的脚本

时间:2008-09-19 20:58:02

标签: php sql mysql utf-8 collation

我是否可以运行SQLPHP脚本来更改数据库中所有表和字段的默认排序规则?

我可以自己写一个,但我认为这应该是在这样的网站上随时可用的东西。如果我能在某人发布之前自己拿出一个,我会自己发布。

17 个答案:

答案 0 :(得分:85)

可以在一个命令中完成(而不是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的{​​{1}}和--password选项。

编辑:为了避免外键问题,添加了mysqlSET foreign_key_checks = 0;

答案 1 :(得分:39)

我认为在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步:
此查询将输出一个查询列表,每个表一个。您必须复制查询列表,并将它们粘贴到命令行或PhpMyAdmin的SQL选项卡中以进行更改。

答案 2 :(得分:27)

好的,我写了这篇文章,考虑到这个帖子中的内容。感谢您的帮助,我希望这个脚本可以帮助其他人。我对它的使用没有任何保证,所以请在运行之前备份。它应该适用于所有数据库;它本身就很好用。

编辑:在顶部添加了要转换为charset / collat​​e的变量。 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>";

?>

答案 3 :(得分:24)

小心!如果你实际上将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上,请不要忘记在与db交互之前添加set NAMES命令,并确保设置字符编码头。

答案 4 :(得分:14)

此PHP代码段将更改数据库中所有表的排序规则。 (它取自this 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 />";
    }
}
?> 

答案 5 :(得分:4)

使用命令行的另一种方法,基于没有awk

的@ david
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

答案 6 :(得分:2)

上面的脚本的更完整版本可以在这里找到:

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

答案 7 :(得分:1)

在上面选择用于转换的所有表的脚本中(使用SHOW TABLES),但是在转换表之前检查表排序规则的方便且可移植的方式。此查询执行此操作:

SELECT table_name
     , table_collation 
FROM information_schema.tables

答案 8 :(得分:1)

Charset和校对不是一回事。排序规则是一组有关如何排序字符串的规则。 charset是一组关于如何表示字符的规则。整理取决于字符集。

答案 9 :(得分:0)

使用我的自定义shell collatedb,它应该可以工作:

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

示例:

collatedb root 0000 myDatabase utf8_bin

答案 10 :(得分:0)

感谢@nlaq的代码,让我开始使用以下解决方案。

我发布了一个WordPress插件,却没有意识到WordPress没有自动设置整理。因此,很多使用该插件的用户最终都应该使用latin1_swedish_ci。{/ 1}。

以下是我添加到插件中以检测utf8_general_ci整理并将其更改为latin1_swedish_ci的代码。

在您自己的插件中使用之前测试此代码!

utf8_general_ci

答案 11 :(得分:0)

一个简单的(哑?)解决方案,使用您的IDE的多选功能:

  1. run&#34; SHOW TABLES;&#34;查询和复制结果列(表名)。
  2. 多选择开头并添加&#34; ALTER TABLE&#34;。
  3. 多选结尾并添加&#34; CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;&#34;
  4. 运行已创建的查询。

答案 12 :(得分:0)

我认为最快的方法是使用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. 更改表格的字符集&#34;整理&#34;字段&#34;操作&#34;标签

  5. 在phpmyadmin 4.0和4.4上测试过,但我觉得可以在所有4.x版本上工作

答案 13 :(得分:0)

如果您没有命令行访问权限或访问编辑INFORMATION_SCHEMA,那么只需使用phpmyadmin即可轻松完成此操作。

首先,在这里听听许多其他答案的建议 - 你真的可以搞砸了,所以做一个备份。现在备份您的备份。如果您的数据编码方式与更改数据的方式不同,这也不太可行。

请注意,您需要找到在开始之前需要更改的有问题的架构和字符编码的确切名称。

  1. 将数据库导出为SQL;复制一份;在您选择的文本编辑器中打开它
  2. 首先查找并替换架构,例如 - find: latin1_swedish_ci ,替换: utf8_general_ci
  3. 如果您需要,请查找并替换字符编码,例如 - 查找: latin1 ,替换: utf8
  4. 创建新的测试数据库并将新的SQL文件上传到phpmyadmin
  5. 这是一种非常简单的方法,但同样,这不会改变数据的编码,因此只能在某些情况下使用。

答案 14 :(得分:0)

我更新了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>";

?>

答案 15 :(得分:0)

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

将[database],[user]和[password]占位符替换为实际值。

Git-bash 用户可以下载此bash script并轻松运行。

答案 16 :(得分:0)

就其价值而言,这里有一个扩展版本的 https://stackoverflow.com/a/42545503/6226915 作为 Yii2 ConsoleController 类,它也可以独立使用:https://gist.github.com/cboulanger/d30c197235a53d9a2331f19a96d6e00d

该脚本修复了一些错误并增加了对全文索引的支持;它还处理 3kb 的常规索引键长度约束。它还将所有表转换为 InnoDB。