如何将整个MySQL数据库字符集和排序规则转换为UTF-8?


459

如何将整个MySQL数据库字符集转换为UTF-8并将排序规则转换为UTF-8?


22
对于以后的访问者:请注意边栏中的相关问题,并使用utf8_unicode_ci而不是utf8_general_ci
2013年

14
如果你想完整的UTF-8支持你可能也想用一个字符集的utf8mb4,而不是utf8utf8仅支持,而不是全方位的基本多文种平面。它需要MySQL 5.5.3或更高版本。
Martin Steel

4
我忘了在上面的评论中提及,如果您切换到utf8mb4您,则还需要将排序规则切换到utf8mb4_unicode_ci
Martin Steel

3
更好的是collat​​ion utf8mb4_unicode_520_ci或最新的可用版本。
瑞克·詹姆斯

@MartinSteel我相信默认情况下是该字符集的排序规则。
VaTo

Answers:


715

使用ALTER DATABASEALTER TABLE命令。

ALTER DATABASE databasename CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE tablename CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

或者,如果您仍在不支持4字节UTF-8的MySQL 5.5.2或更旧版本上,请使用utf8代替utf8mb4

ALTER DATABASE databasename CHARACTER SET utf8 COLLATE utf8_unicode_ci;
ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

12
CONVERT TO技术假定文本已正确存储在其他字符集(例如latin1)中,并且没有被弄乱(例如,UTF-8字节被挤入了latin1列而未转换为latin1)。
里克·詹姆斯

1
这将重建表,使其在大型生产系统上不可行。如果确定latin1列中仅存储ASCII字符,是否可以在不重建表的情况下更改表的字符集/排序规则?
安德鲁

@Andrew大型生产系统通常具有用于维护的镜像DB。
BalusC

1
将字符集更改为utf8会将我的数据类型从文本更改为中文本。是预期的吗?
杰里

1
@Jerry可能是因为:“如果将列转换为utf8,则每个字符可能需要最多三个字节,最大可能的长度为3×65,535 = 196,605字节。该长度不适合TEXT列的长度字节,因此MySQL将数据类型转换为MEDIUMTEXT,这是最小的字符串类型,长度字节可以记录该字符串类型的值196,605。类似地,VARCHAR列可能会转换为MEDIUMTEXT。更改字符集
jabbascript

129
  1. 备份!

  2. 然后,您需要在数据库上设置默认字符集。这不会转换现有表,而只会为新创建的表设置默认值。

    ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
  3. 然后,您将需要转换所有现有表及其列上的字符集。假设您当前的数据实际上在当前字符集中。如果您将列设置为一个字符集,但您的数据确实存储在另一个字符集中,则需要查看MySQL手册以了解如何处理该字符集。

    ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

44
注意:ALTER TABLE表名CHARACTER SET utf8仅在用于新创建的列的表上设置默认字符集。它不会转换已具有字符集的现有列。
newspire 2011年

我应该先阅读备份备份...但是我的运气是它在开发环境中。所以我对你投反对票!
DominikAngerer 2014年

4
@DominikAngerer:什么坏了?
cic

16
请注意,utf8_general_ci不再推荐最佳做法。从MySQL 5.5.3开始,您应该使用utf8mb4而不是utf8。它们都引用UTF-8编码,但是较旧的版本utf8具有MySQL特定的限制,无法使用上面编号的字符0xFFFD
u01jmg3

76

在命令行外壳上

如果您是命令行外壳程序之一,则可以非常快速地执行此操作。只需填写“ dbname”:D

DB="dbname"
(
    echo 'ALTER DATABASE `'"$DB"'` CHARACTER SET utf8 COLLATE utf8_general_ci;'
    mysql "$DB" -e "SHOW TABLES" --batch --skip-column-names \
    | xargs -I{} echo 'ALTER TABLE `'{}'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;'
) \
| mysql "$DB"

一线可轻松复制/粘贴

DB="dbname"; ( echo 'ALTER DATABASE `'"$DB"'` CHARACTER SET utf8 COLLATE utf8_general_ci;'; mysql "$DB" -e "SHOW TABLES" --batch --skip-column-names | xargs -I{} echo 'ALTER TABLE `'{}'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;' ) | mysql "$DB"

2
您能在此详细说明吗ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DB="dbname"
steros 2014年

@ 4485670您需要在命令行shell上运行它。如果只有MySQL客户端连接可用,请使用下面的sdfor代码。
阿诺德·丹尼尔斯

6
这段代码很好用,只需记住在必要时在mysql之后添加-h [主机名] -u [用户名] -p [密码]。
驱散

3
您可能需要在实际系统上禁用外键检查: DB="db_name"; ( echo 'ALTER DATABASE '“ $ DB”'`CHARACTER SET utf8 COLLATE utf8_general_ci;'; mysql --uuser -ppassword -hhost“ $ DB” -e“ SHOW TABLES” –batch --skip-column-names | xargs -I {} echo'SET foreign_key_checks = 0; 将表'{}'转换为字符集utf8集合utf8_general_ci;' )| mysql -uuser -ppassword -hhost“ $ DB”`
Adam Nelson

1
在我使用“显示其中Table_Type ='BASE TABLE'的完整表”而不是““ SHOW TABLES”之前,对我不起作用
Brian Peterson

68

您可以创建sql以使用以下命令更新所有表:

SELECT CONCAT("ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," CHARACTER SET utf8 COLLATE utf8_general_ci;   ",
    "ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  ") 
    AS alter_sql
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = your_database_name;

捕获输出并运行它。

阿诺德·丹尼尔斯的上述回答更为优雅。


为什么要添加两个alter table查询?一个还不够?
阿克沙伊

7
@Akshay,好问题。第一个更改表查询为新列设置默认值,第二个更改表查询转换现有列。
UnlimitedInfinity 2014年

4
仅供参考:根据dev.mysql.com/doc/refman/5.5/zh-CN/alter-table.html MySQL文档,ALTER语句的“转换为字符集”版本只需一步即可:“更改表默认值字符集所有字符列(CHAR,VARCHAR,TEXT)转换为新字符集...
devGuy 2015年

2
我有这样的错误#1054 -在“where子句”未知列“webdb_playground”,但我敢肯定,我的数据库是正确的
雅尼斯DRAN

1
@YannisDran您的数据库名称可能没有在字符串中,这样WHERE TABLE_SCHEMA=webdb_playground就给您带来了未知的列错误,但WHERE TABLE_SCHEMA="webdb_playground"可以成功。尝试尝试其他任何人遇到的情况。
jabbascript

17

在继续之前,请确保您:已完成完整的数据库备份!

步骤1:数据库级别更改

  • 识别数据库的排序规则和字符集

    SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM 
    information_schema.SCHEMATA S
    WHERE schema_name = 'your_database_name'
    AND
    (DEFAULT_CHARACTER_SET_NAME != 'utf8'
        OR
     DEFAULT_COLLATION_NAME not like 'utf8%');
  • 修复数据库排序规则

    ALTER DATABASE databasename CHARACTER SET utf8 COLLATE utf8_unicode_ci;

步骤2:表级别更改

  • 标识具有错误字符集或排序规则的数据库表

    SELECT CONCAT(
    'ALTER TABLE ',  table_name, ' CHARACTER SET utf8 COLLATE utf8_general_ci;  ', 
    'ALTER TABLE ',  table_name, ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  ')
    FROM information_schema.TABLES AS T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` AS C
    WHERE C.collation_name = T.table_collation
    AND T.table_schema = 'your_database_name'
    AND
    (C.CHARACTER_SET_NAME != 'utf8'
        OR
     C.COLLATION_NAME not like 'utf8%')
  • 调整表格列的排序规则和字符集

捕获较高的sql输出并运行它。(如下所示)

ALTER TABLE rma CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_history CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_history CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_products CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_products CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_report_period CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_report_period CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_reservation CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_reservation CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_supplier_return CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_supplier_return CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_supplier_return_history CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_supplier_return_history CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;  
ALTER TABLE rma_supplier_return_product CHARACTER SET utf8 COLLATE utf8_general_ci;ALTER TABLE rma_supplier_return_product CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; 

请参阅:https : //confluence.atlassian.com/display/CONFKB/How+to+Fix+the+Collat​​ion+and+Character+Set+of+a+MySQL+Database


1
当前,此脚本对数据库使用'utf8_unicode_ci',对表使用'utf8_general_ci'-这是故意的吗?(我认为两者都应使用相同的字符集)
gmcnaughton 16'-

stackoverflow.com/questions/10957238/…在这里留下了更完整的答案
VH

8

使用HeidiSQL。它的免费和非常好的数据库工具。

在工具菜单中,输入批量表编辑器

选择完整的数据库或选择要转换的表,

  • 勾选更改默认排序规则:utf8mb4_general_ci
  • 勾选转换为字符集:utf8

执行

只需几秒钟,即可将完整的数据库从拉丁语转换为utf8。

奇迹般有效 :)

HeidiSQL默认情况下以utf8连接,因此在检查表数据时,现在应将任何特殊字符视为字符(æøå),而不应视为已编码。

从拉丁语迁移到utf8时,真正的陷阱是确保pdo与utf8字符集连接。如果不是这样,您将把垃圾数据插入到utf8表中,并在您的网页上各处出现问号,使您认为表数据不是utf8 ...


您能详细说明一下吗?我确实有这个问题-特殊字符和空格显示为问号。我正在尝试使用PHPMyAdmin在MAMP中转换数据库。离线开发后,我现在发现我的主机不支持utf8mb4。我没有Windows,所以无法使用HeidiSQL。有什么办法可以用PHPMyAdmin做到这一点?
RexTheRunt

像这样 特别是你有很多桌子。
tyan

尝试转换CHARSET时出现错误:SQL错误(1025):重命名错误...但这是一个了不起的SQL管理器工具!
marcolopes

如果有人需要heidisql的良好概述和教程,请查阅本文
DougB

6

受@sdfor注释的启发,这是一个可以完成工作的bash脚本

#!/bin/bash

printf "### Converting MySQL character set ###\n\n"

printf "Enter the encoding you want to set: "
read -r CHARSET

# Get the MySQL username
printf "Enter mysql username: "
read -r USERNAME

# Get the MySQL password
printf "Enter mysql password for user %s:" "$USERNAME"
read -rs PASSWORD

DBLIST=( mydatabase1 mydatabase2 )

printf "\n"


for DB in "${DBLIST[@]}"
do
(
    echo 'ALTER DATABASE `'"$DB"'` CHARACTER SET utf8 COLLATE `'"$CHARSET"'`;'
    mysql "$DB" -u"$USERNAME" -p"$PASSWORD" -e "SHOW TABLES" --batch --skip-column-names \
    | xargs -I{} echo 'ALTER TABLE `'{}'` CONVERT TO CHARACTER SET utf8 COLLATE `'"$CHARSET"'`;'
) \
| mysql "$DB" -u"$USERNAME" -p"$PASSWORD"

echo "$DB database done..."
done

echo "### DONE ###"
exit

4

如果数据使用不同的字符集,则可以考虑从http://dev.mysql.com/doc/refman/5.0/en/charset-conversion.html中获取此代码段

如果该列具有非二进制数据类型(CHAR,VARCHAR,TEXT),则其内容应使用列字符集而不是其他字符集进行编码。如果内容以不同的字符集编码,则可以先将该列转换为使用二进制数据类型,然后再转换为具有所需字符集的非二进制列。

这是一个例子:

 ALTER TABLE t1 CHANGE c1 c1 BLOB;
 ALTER TABLE t1 CHANGE c1 c1 VARCHAR(100) CHARACTER SET utf8;

确保选择正确的排序规则,否则可能会遇到唯一的键冲突。例如,在某些整理中,Éleanore和Eleanore可能被认为是相同的。

在旁边:

我遇到的情况是,即使电子邮件中某些字符以“ UTF-8”形式存储,电子邮件中的某些字符还是“中断”了。如果要使用utf8数据发送电子邮件,则可能还希望将电子邮件转换为以UTF8格式发送。

在PHPMailer中,只需更新以下行: public $CharSet = 'utf-8';


4

对于具有大量表的数据库,可以使用以下简单的php脚本来更新数据库和所有表的字符集:

$conn = mysqli_connect($host, $username, $password, $database);

if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}

$alter_database_charset_sql = "ALTER DATABASE ".$database." CHARACTER SET utf8 COLLATE utf8_unicode_ci";
mysqli_query($conn, $alter_database_charset_sql);

$show_tables_result = mysqli_query($conn, "SHOW TABLES");
$tables  = mysqli_fetch_all($show_tables_result);

foreach ($tables as $index => $table) {
  $alter_table_sql = "ALTER TABLE ".$table[0]." CONVERT TO CHARACTER SET utf8  COLLATE utf8_unicode_ci";
  $alter_table_result = mysqli_query($conn, $alter_table_sql);
  echo "<pre>";
  var_dump($alter_table_result);
  echo "</pre>";
}

我们从哪里运行此脚本?
Yannis Dran

1
@YannisDran没关系,只要执行它的IP可以访问数据库即可。确保先备份!
丹·卢卡斯

好,我们如何运行它?我们是否必须将其上传到服务器上,然后运行输入其位置的路径?
Yannis Dran,

4
DELIMITER $$  

CREATE PROCEDURE `databasename`.`update_char_set`()  

BEGIN  
 DECLARE done INT DEFAULT 0;  
 DECLARE t_sql VARCHAR(256);  
 DECLARE tableName VARCHAR(128);  
 DECLARE lists CURSOR FOR SELECT table_name FROM `information_schema`.`TABLES` WHERE table_schema = 'databasename';  
 DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;  
 OPEN lists;  
 FETCH lists INTO tableName;  
 REPEAT  
    SET @t_sql = CONCAT('ALTER TABLE ', tableName, ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci');  
    PREPARE stmt FROM @t_sql;  
    EXECUTE stmt;  
    DEALLOCATE PREPARE stmt;  
 FETCH lists INTO tableName;  
 UNTIL done END REPEAT;  
 CLOSE lists;  
END$$  

DELIMITER ;  

CALL databasename.update_char_set();

谢谢,这是实际显示如何对整个数据库(即每个表)进行操作的少数答案之一。像魅力一样工作。
Machisuji '19

3
mysqldump -uusername -ppassword -c -e --default-character-set=utf8 --single-transaction --skip-set-charset --add-drop-database -B dbname > dump.sql
cp dump.sql dump-fixed.sql
vim dump-fixed.sql


:%s/DEFAULT CHARACTER SET latin1/DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci/
:%s/DEFAULT CHARSET=latin1/DEFAULT CHARSET=utf8/
:wq

mysql -uusername -ppassword < dump-fixed.sql

3

最安全的方法是先将列修改为二进制类型,然后使用所需的字符集将其修改回其类型。

每个列类型都有其各自的二进制类型,如下所示:

  1. CHAR => BINARY
  2. 文字=> BLOB
  3. TINYTEXT => TINYBLOB
  4. MEDIUMTEXT => MEDIUMBLOB
  5. LONGTEXT => LONGBLOB
  6. VARCHAR => VARBINARY

例如。:

ALTER TABLE [TABLE_SCHEMA].[TABLE_NAME] MODIFY [COLUMN_NAME] VARBINARY;

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%');

在所有列上执行此操作之后,您将在所有表上执行此操作:

ALTER TABLE [TABLE_SCHEMA].[TABLE_NAME] CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

要为您的所有表生成此查询,请使用以下查询:

SELECT
CONCAT('ALTER TABLE ', TABLE_SCHEMA, '.', TABLE_NAME, ' CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_COLLATION NOT LIKE 'utf8%'
and TABLE_SCHEMA in ('[TABLE_SCHEMA]');

既然您已经修改了所有列和表,请在数据库上执行相同的操作:

ALTER DATABASE [DATA_BASE_NAME] CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;

1

如果您无法使表转换,或者表始终设置为某些非utf8字符集,但是您想要utf8,则最好的选择是清除它并重新开始并显式指定:

create database database_name character set utf8;

0

唯一对我有用的解决方案:http : //docs.moodle.org/23/en/Converting_your_MySQL_database_to_UTF8

转换包含表的数据库

mysqldump -uusername -ppassword -c -e --default-character-set=utf8 --single-transaction --skip-set-charset --add-drop-database -B dbname > dump.sql

cp dump.sql dump-fixed.sql
vim dump-fixed.sql

:%s/DEFAULT CHARACTER SET latin1/DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci/
:%s/DEFAULT CHARSET=latin1/DEFAULT CHARSET=utf8/
:wq

mysql -uusername -ppassword < dump-fixed.sql


0

要将数据库本身的字符集编码更改为UTF-8,请在mysql>提示符下键入以下命令。将DBNAME替换为数据库名称:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

0

您也可以使用数据库工具Navicat,它更容易完成。

  • 西瓦

右键单击您的数据库,然后在下拉菜单中选择所需的数据库属性和更改

在此处输入图片说明


0

命令行解决方案和排除视图

我只是在为@Jasny 回答其他问题,例如@Brian在数据库中拥有视图的其他人。

如果您有这样的错误:

ERROR 1347 (HY000) at line 17: 'dbname.table_name' is not of type 'BASE TABLE'

这是因为您可能有视图,因此需要排除它们。但是当试图排除它们时,MySQL返回2列而不是1列。

SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE';
-- table_name1  BASE TABLE
-- table_name2  BASE TABLE

因此,我们必须使Jasny的命令适应awk于仅提取包含表名的第一列。

DB="dbname"
(
    echo 'ALTER DATABASE `'"$DB"'` CHARACTER SET utf8 COLLATE utf8_general_ci;'
    mysql "$DB" -e "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" --batch --skip-column-names \
    | awk '{print $1 }' \
    | xargs -I{} echo 'ALTER TABLE `'{}'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;'
) \
| mysql "$DB"

一线可轻松复制/粘贴

DB="dbname"; ( echo 'ALTER DATABASE `'"$DB"'` CHARACTER SET utf8 COLLATE utf8_general_ci;'; mysql "$DB" -e "SHOW FULL TABLES WHERE Table_Type = 'BASE TABLE'" --batch --skip-column-names | awk '{print $1 }' | xargs -I{} echo 'ALTER TABLE `'{}'` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;' ) | mysql "$DB"

-1

要将字符集编码更改为UTF-8,请按照PHPMyAdmin中的简单步骤进行操作

  1. 选择你的数据库 SS

  2. 前往运营 SS

  3. 在“操作”选项卡的底部排序规则下拉菜单中,选择所需的编码ie(utf8_general_ci),并选中以下复选框:(1)更改所有表排序规则,(2)更改所有表列排序规则。然后点击开始。

SS

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.