如何将整个 MySQL 数据库字符集和排序规则转换为 UTF-8?
Posted
技术标签:
【中文标题】如何将整个 MySQL 数据库字符集和排序规则转换为 UTF-8?【英文标题】:How to convert an entire MySQL database characterset and collation to UTF-8? 【发布时间】:2011-09-01 05:13:49 【问题描述】:如何将整个 mysql 数据库字符集转换为 UTF-8 并将排序规则转换为 UTF-8?
【问题讨论】:
致以后的访问者:注意边栏中的相关问题,并使用utf8_unicode_ci
,而不是utf8_general_ci
。
如果您想要完整的 UTF-8 支持,您可能还需要使用 utf8mb4
而不是 utf8
的字符集,因为 utf8
仅支持基本的多语言平面,而不是全系列。它需要 MySQL 5.5.3 或更高版本。
我忘了在上面的评论中提到,如果你切换到utf8mb4
,你还需要将排序规则切换到utf8mb4_unicode_ci
更好的是,排序规则utf8mb4_unicode_520_ci
,或者任何最新的可用版本。
@MartinSteel 我相信这是该字符集的默认排序规则。
【参考方案1】:
您可以创建 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";
捕获输出并运行它。
Arnold Daniels 上面的回答更优雅。
【讨论】:
为什么要添加两个alter table query?一个还不够? @Akshay,好问题。第一个 alter-table 查询为新列设置默认值,第二个 alter-table 查询转换现有列。 仅供参考:根据dev.mysql.com/doc/refman/5.5/en/alter-table.html MySQL 文档,ALTER 语句的“CONVERT TO CHARACTER SET”版本在一步中完成:“更改表默认字符集和 将所有字符列(CHAR、VARCHAR、TEXT)转换为新字符集 ... 我有这个错误 #1054 - 'where 子句'中的未知列 'webdb_playground' 但我确定我的数据库是正确的 @YannisDran 您的数据库名称可能不在字符串中,因此WHERE TABLE_SCHEMA=webdb_playground
给您未知列错误,但WHERE TABLE_SCHEMA="webdb_playground"
会成功。可以尝试一下,以防其他人遇到这种情况。【参考方案2】:
要将字符集编码更改为 UTF-8,请按照 phpMyAdmin 中的简单步骤操作
选择您的数据库
转到操作
在操作选项卡的底部排序规则下拉菜单中,选择您想要的编码,即 (utf8_general_ci),并选中复选框 (1) 更改所有表排序规则,(2) 更改所有表列排序规则。然后点击Go。【讨论】:
【参考方案3】:命令行解决方案和排除视图
我只是为@Brian
和我在我们的数据库中有视图的其他人完成@Jasny 的answer。
如果你有这样的错误:
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
所以我们必须使用 awk
调整 Jasny 的命令,以仅提取包含表名的第一列。
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"
【讨论】:
【参考方案4】:最安全的方法是先将列修改为二进制类型,然后使用所需的字符集将其修改回它的类型。
每种列类型都有其各自的二进制类型,如下:
-
CHAR => 二进制
文本 => BLOB
TINYTEXT => TINYBLOB
MEDIUMTEXT => MEDIUMBLOB
LONGTEXT => LONGBLOB
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;
【讨论】:
【参考方案5】: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();
【讨论】:
谢谢,这是少数几个实际展示如何对整个数据库(即每个表)执行此操作的答案之一。像魅力一样工作。【参考方案6】:使用ALTER DATABASE
和ALTER 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;
【讨论】:
CONVERT TO
技术假定文本正确存储在其他字符集(例如 latin1)中,并且没有被破坏(例如 UTF-8 字节塞进 latin1未转换为 latin1) 的列。
这会重建表,使其在大型生产系统上不可行。如果确定只有 ASCII 字符存储在 latin1 列中,是否可以在不重建的情况下更改表字符集/排序规则?
@Andrew 大型生产系统通常有一个镜像数据库用于维护。
将字符集更改为 utf8 会将我的数据类型从文本更改为中文本。是预期的吗?
@Jerry 可能是因为:“如果将列转换为 utf8,每个字符可能需要最多三个字节,最大可能长度为 3 × 65,535 = 196,605 字节。该长度不适合在 TEXT 列的长度字节中,因此 MySQL 将数据类型转换为 MEDIUMTEXT,这是长度字节可以记录值 196,605 的最小字符串类型。类似地,VARCHAR 列可能会转换为 MEDIUMTEXT。 Changing the Character Set【参考方案7】:
您还可以使用数据库工具 Navicat,这更容易。
湿婆。右键单击您的数据库并在下拉菜单中根据需要选择数据库属性和更改
【讨论】:
【参考方案8】:进行备份!
然后你需要在数据库上设置默认的字符集。这不会转换现有表,它只会为新创建的表设置默认值。
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
然后,您需要转换所有现有表及其列上的字符集。这假设您当前的数据实际上在当前字符集中。如果您的列设置为一个字符集,但您的数据确实存储在另一个字符集中,那么您需要查看MySQL manual 以了解如何处理此问题。
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
【讨论】:
注意:ALTER TABLE tablename CHARACTER SET utf8 仅在用于新创建列的表上设置默认字符集。它不会转换已经设置了字符集的现有列。 我应该先阅读备份备份...但我的运气是它在开发环境中。所以我的赞成票给你! @DominikAngerer:什么坏了? 请注意,utf8_general_ci
不再是推荐的最佳做法。从 MySQL 5.5.3 开始,您应该使用 utf8mb4
而不是 utf8
。它们都引用 UTF-8 编码,但旧的 utf8
有一个特定于 MySQL 的限制,阻止使用编号高于 0xFFFD
的字符。【参考方案9】:
要将数据库本身的字符集编码更改为 UTF-8,请在 mysql> 提示符下键入以下命令。将 DBNAME 替换为数据库名称:
ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;
【讨论】:
【参考方案10】: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
【讨论】:
【参考方案11】:在继续之前,请确保您: 已完成完整的数据库备份!
第 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+Collation+and+Character+Set+of+a+MySQL+Database
【讨论】:
目前这个脚本对数据库使用'utf8_unicode_ci',而对表使用'utf8_general_ci'——这是故意的吗? (我认为两者都应该使用相同的字符集) ***.com/questions/10957238/… 在这里留下了更完整的答案【参考方案12】:alter table table_name charset = 'utf8';
这是我可以用于我的案例的简单查询,您可以根据您的要求更改 table_name。
【讨论】:
通常情况下,答案应附有对您建议做什么的解释。【参考方案13】:受@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
【讨论】:
【参考方案14】:对于具有大量表的数据库,您可以使用简单的 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>";
【讨论】:
我们从哪里运行这个脚本? @YannisDran 没关系,只要您执行它的 IP 可以访问数据库。请务必先备份! 很好,我们如何运行它?我们是否必须将其上传到服务器然后运行输入其位置的路径?【参考方案15】:使用HeidiSQL。它是免费且非常好的数据库工具。
从工具菜单,进入批量表格编辑器
选择完整的数据库或选择要转换的表,
勾选更改默认排序规则:utf8mb4_general_ci 勾选转换为字符集:utf8执行
这将在几秒钟内将完整的数据库从拉丁语转换为 utf8。
像魅力一样工作:)
HeidiSQL 默认连接为 utf8,因此在检查表数据时,任何特殊字符现在都应视为字符 (æ ø å) 而不是编码。
从 latin 迁移到 utf8 的真正陷阱是确保 pdo 与 utf8 字符集连接。如果不是,您将在 utf8 表格中插入垃圾数据,并且网页上到处都是问号,让您认为表格数据不是 utf8...
【讨论】:
您能详细说明一下吗?我有这个问题 - 特殊字符和空格显示为问号。我正在尝试使用 PHPMyAdmin 在 MAMP 中转换数据库。离线开发后,我现在发现我的主机不支持 utf8mb4。我没有 Windows,所以不能使用 HeidiSQL。有没有办法使用 PHPMyAdmin 实现这一目标? 喜欢这样。尤其是你有很多桌子。 尝试转换 CHARSET 时出现错误:SQL 错误 (1025):重命名时出错...但这是一个了不起的 SQL 管理器工具! 如果有人需要很好的 heidisql 概述和教程,check out this article。【参考方案16】:如果数据不在同一个字符集中,您可以考虑使用来自http://dev.mysql.com/doc/refman/5.0/en/charset-conversion.html的这个sn-p
如果列具有非二进制数据类型(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';
【讨论】:
【参考方案17】:在命令行 shell 上
如果您是命令行 shell 之一,您可以非常快速地完成此操作。只需填写“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"
【讨论】:
你能把更多细节写在这我得到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"
@4485670 你需要在command line shell 上运行它。如果您只有 MySQL 客户端连接可用,请使用下面的 sdfor 代码。
这段代码很好用,只要记得在mysql后面加-h [hostname] -u [username] -p[password] 就行了。
您可能希望在真实系统上禁用外键检查: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; ALTER TABLE ''
CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;' ) | mysql -uuser -ppassword -hhost "$DB"`
在我使用“显示 Table_Type = 'BASE TABLE' 的完整表格”而不是“显示表格”之前对我不起作用【参考方案18】:
唯一对我有用的解决方案: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
【讨论】:
【参考方案19】:如果您无法让您的表格进行转换,或者您的表格始终设置为某些非 utf8 字符集,但您想要 utf8,您最好的办法可能是清除它并重新开始并明确指定:
create database database_name character set utf8;
【讨论】:
以上是关于如何将整个 MySQL 数据库字符集和排序规则转换为 UTF-8?的主要内容,如果未能解决你的问题,请参考以下文章
如何在整个数据库中更改 CHARACTER SET(和 COLLATION)?
如何在整个数据库中更改 CHARACTER SET(和 COLLATION)?