如何在整个数据库中更改 CHARACTER SET(和 COLLATION)?
Posted
技术标签:
【中文标题】如何在整个数据库中更改 CHARACTER SET(和 COLLATION)?【英文标题】:How to change the CHARACTER SET (and COLLATION) throughout a database? 【发布时间】:2011-08-19 21:06:31 【问题描述】:我们以前的程序员在表 (mysql) 中设置了错误的排序规则。他用拉丁排序规则设置它,当它应该是 UTF8 时,现在我遇到了问题。每条带有中日字符的记录都变成了???字符。
是否可以更改排序规则并取回字符的详细信息?
【问题讨论】:
MySql alter table Collation的可能重复 排序规则与'???'有什么关系字符集?我认为这与字符集有关? 我正在更改标题以反映意图。更改 database 的 default 排序规则远低于预期。 【参考方案1】:更改数据库排序规则:
ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
更改表排序规则:
ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
更改列排序规则:
ALTER TABLE <table_name> MODIFY <column_name> VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
utf8mb4_0900_ai_ci
各部分是什么意思?
3 bytes -- utf8
4 bytes -- utf8mb4 (new)
v4.0 -- _unicode_
v5.20 -- _unicode_520_
v9.0 -- _0900_ (new)
_bin -- just compare the bits; don't consider case folding, accents, etc
_ci -- explicitly case insensitive (A=a) and implicitly accent insensitive (a=á)
_ai_ci -- explicitly case insensitive and accent insensitive
_as (etc) -- accent-sensitive (etc)
_bin -- simple, fast
_general_ci -- fails to compare multiletters; eg ss=ß, somewhat fast
... -- slower
_0900_ -- (8.0) much faster because of a rewrite
更多信息:
What are the differences between utf8_general_ci and utf8_unicode_ci? What's the difference between utf8_general_ci and utf8_unicode_ci? How to change collation of database, table, column? What's the difference between utf8_general_ci and utf8_unicode_ci?【讨论】:
当心CHARACTER SET utf8
将默认为utf8_general_ci
,但如果需要,您也可以像ALTER DATABASE <database_name> CHARACTER SET utf8 COLLATE utf8_unicode_ci;
这样定义排序规则
...我建议你测试一下create table testit(a varchar(1)); show create table testit \G drop table testit;
只想提一下,第二个会把排序规则改成utf8_general_ci
;如果你想把它改成utf8_unicode_ci
,你可以定义排序规则:ALTER TABLE <table_name> CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
。正如@KCD 所指出的,这在表上的工作方式与在数据库上的工作方式完全相同。
最好执行以下操作以获得完整的 utf8 支持 ALTER DATABASE <database_name> CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
。您应该对其他两个语句执行相同的操作。
你真的需要使用“ALTER TABLE 以下是如何更改所有数据库/表/列。运行这些查询,它们将输出将整个架构转换为 utf8 所需的所有后续查询。希望这会有所帮助!
-- 更改数据库默认排序规则
SELECT DISTINCT concat('ALTER DATABASE `', TABLE_SCHEMA, '` CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.tables
where TABLE_SCHEMA like 'database_name';
-- 更改 TABLE 排序规则/字符集
SELECT concat('ALTER TABLE `', TABLE_SCHEMA, '`.`', table_name, '` CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.tables
where TABLE_SCHEMA like 'database_name';
-- 更改 COLUMN 排序规则/字符集
SELECT concat('ALTER TABLE `', t1.TABLE_SCHEMA, '`.`', t1.table_name, '` MODIFY `', t1.column_name, '` ', t1.data_type , '(' , t1.CHARACTER_MAXIMUM_LENGTH , ')' , ' CHARACTER SET utf8 COLLATE utf8_unicode_ci;')
from information_schema.columns t1
where t1.TABLE_SCHEMA like 'database_name' and t1.COLLATION_NAME = 'old_charset_name';
【讨论】:
好。 !我试图解决同样的问题大约需要一个小时。我使用这 3 个命令,我看到字符集发生了变化。但主要问题仍然是我。如果我直接写入数据库,那么一切都在我的浏览器中显示得很好。但是如果我从网站表单中添加了一些内容,数据库中的结果只是??????。有什么我应该考虑的吗?我的网络应用是一个 .NET MVC 应用。 保存到对未来项目有用的查询中。 我建议进行一些修改,因为这些自动查询的使用还不是很安全。 CHARACTER_MAXIMUM_LENGTH 仍然存在问题:当您更改时,原来的可能太高了,例如latin1_swedish_ci 到 utf8_unicode_ci。 这是一个很好的答案。我有三个 cmets/问题: 1) 为什么在 COLUMN 代码中使用“t1”?我认为没有任何必要。 2) 为什么是“t1.data_type, '(', t1.CHARACTER_MAXIMUM_LENGTH, ')'”而不仅仅是“t1.column_type”? 3) 为什么大写和小写的混合 - TABLE_SCHEMA vs table_name 等等? 请注意,这会将列更改为 NULLable 并删除其默认值(至少在 MySQL 中)。【参考方案3】:请注意,在 Mysql 中,utf8
字符集只是真正的 UTF8 字符集的一个子集。为了节省一个字节的存储空间,Mysql 团队决定只存储一个 UTF8 字符的三个字节,而不是完整的四个字节。这意味着不完全支持某些东亚语言和表情符号。为确保可以存储所有 UTF8 字符,请在 Mysql 中使用 utf8mb4
数据类型和 utf8mb4_bin
或 utf8mb4_general_ci
。
【讨论】:
现在,建议使用utf8mb4_unicode_ci
而不是utf8mb4_general_ci
。见***.com/questions/766809/… 和drupal.stackexchange.com/questions/166405/…【参考方案4】:
除了 David Whittaker 发布的内容之外,我还创建了一个查询,该查询生成完整的表和列更改语句,该语句将转换每个表。运行可能是个好主意
设置会话 group_concat_max_len = 100000;
首先要确保您的组 concat 不会超过 here 所看到的非常小的限制。
SELECT a.table_name, concat('ALTER TABLE ', a.table_schema, '.', a.table_name, ' DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci, ',
group_concat(distinct(concat(' MODIFY ', column_name, ' ', column_type, ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ', if (is_nullable = 'NO', ' NOT', ''), ' NULL ',
if (COLUMN_DEFAULT is not null, CONCAT(' DEFAULT \'', COLUMN_DEFAULT, '\''), ''), if (EXTRA != '', CONCAT(' ', EXTRA), '')))), ';') as alter_statement
FROM information_schema.columns a
INNER JOIN INFORMATION_SCHEMA.TABLES b ON a.TABLE_CATALOG = b.TABLE_CATALOG
AND a.TABLE_SCHEMA = b.TABLE_SCHEMA
AND a.TABLE_NAME = b.TABLE_NAME
AND b.table_type != 'view'
WHERE a.table_schema = ? and (collation_name = 'latin1_swedish_ci' or collation_name = 'utf8mb4_general_ci')
GROUP BY table_name;
上一个答案之间的区别在于它使用 utf8 而不是 ut8mb4 并且使用 t1.data_type 和 t1.CHARACTER_MAXIMUM_LENGTH 不适用于枚举。此外,我的查询不包括视图,因为它们必须单独更改。
我只是使用 Perl 脚本将所有这些更改作为数组返回并对其进行迭代,修复了太长的列(通常它们是 varchar(256),而数据中通常只有 20 个字符,所以这是一个简单的解决方法)。
从 latin1 -> utf8mb4 更改时,我发现一些数据已损坏。似乎列中的 utf8 编码 latin1 字符会在转换中出错。我只是在更改前后保存了我知道会在内存中出现问题的列中的数据,然后比较它们并生成更新语句来修复数据。
【讨论】:
【参考方案5】:here 很好地描述了这个过程。然而,一些不适合拉丁空间的角色永远消失了。 UTF-8 是 latin1 的 SUPERSET。不是反过来。大多数都适合单字节空间,但任何未定义的都不会(检查 latin1 列表 - 并非所有 256 个字符都已定义,具体取决于 mysql 的 latin1 定义)
【讨论】:
以上是关于如何在整个数据库中更改 CHARACTER SET(和 COLLATION)?的主要内容,如果未能解决你的问题,请参考以下文章
如何在整个数据库中更改 CHARACTER SET(和 COLLATION)?
如何更改 Amazon Aurora DB 中的 character_set_server?