排序规则更改后替换多个表中的多个外来字符

Replace multiple foreign characters in multiple tables after collation change

我有一个 WordPress 网站,其中排序规则设置为 utf8_unicode_ci,我不得不使用立陶宛语字符 (Ą ą Č č etc.)。所有这些字符的编码和保存如下 (Ä„ , Ä… , ÄŒ , Ä etc).

我已将排序规则更改为 utf8mb4_unicode_ci,并且所有新记录都已保存并正确显示。但是,所有旧记录的显示与它们在数据库中的显示完全相同 (Ä„ , Ä… , ÄŒ , Ä etc)

如何替换多个 table 中的多个字符以匹配当前排序规则?

非常感谢任何帮助或指导。

编辑更多信息

基本上,该站点 运行 在不受支持的服务器上运行。在 phpMyAdmin 的数据库服务器部分,我可以看到以下信息:

Server: Localhost via UNIX socket
Software: MySQL
Software version: 5.1.58-1~dotdeb.0-log - (Debian)
Protocol version: 10
User: srvmtb_mtbWP@localhost
Server charset: UTF-8 Unicode (utf8)

这是旧 table 的创建 table(为清楚起见,删除了大部分字段):

CREATE TABLE IF NOT EXISTS `wp_posts` (
  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `post_content` longtext COLLATE utf8_unicode_ci NOT NULL,
  `post_title` text COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `post_name` (`post_name`(191)),
  KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),
  KEY `post_parent` (`post_parent`),
  KEY `post_author` (`post_author`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

这里是数据库导出时生成的 INSERT 的例子:

INSERT INTO `wp_posts` (`ID`, `post_content`, `post_title`) VALUES
(1, 'Tomas TomÄ—nas', '');

所以我像这样导出整个数据库并导入到较新的服务器中。这是数据库服务器信息:

Server: Localhost via UNIX socket
Server type: MariaDB
Server version: 10.0.25-MariaDB - MariaDB Server
Protocol version: 10
User: woalba@localhost
Server charset: UTF-8 Unicode (utf8)

更新后,我 运行 对每个 table 进行了以下查询:

ALTER TABLE wp_posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

现在,每条新记录都使用正确的字符插入和检索,没有任何问题,但是所有旧记录都使用 Ä—.

等奇怪字符检索

如果有任何其他重要信息需要我提供 - 请询问。

提前致谢。

使用 SHOW CREATE 编辑 TABLE

    CREATE TABLE `wp_posts` (  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `post_author` bigint(20) unsigned NOT NULL DEFAULT '0', 
 `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
 `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
 `post_content` longtext COLLATE utf8_unicode_ci NOT NULL,  
`post_title` text COLLATE utf8_unicode_ci NOT NULL,  
`post_excerpt` text COLLATE utf8_unicode_ci NOT NULL, 
 `post_status` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'publish',
  `comment_status` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'open', 
 `ping_status` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'open', 
 `post_password` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
 `post_name` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
 `to_ping` text COLLATE utf8_unicode_ci NOT NULL, 
 `pinged` text COLLATE utf8_unicode_ci NOT NULL,  
`post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
 `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
 `post_content_filtered` longtext COLLATE utf8_unicode_ci NOT NULL, 
 `post_parent` bigint(20) unsigned NOT NULL DEFAULT '0', 
 `guid` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
 `menu_order` int(11) NOT NULL DEFAULT '0', 
 `post_type` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'post',
  `post_mime_type` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 
 `comment_count` bigint(20) NOT NULL DEFAULT '0',  PRIMARY KEY (`ID`), 
 KEY `post_name` (`post_name`(191)),  
KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`),  
KEY `post_parent` (`post_parent`),  
KEY `post_author` (`post_author`)) ENGINE=MyISAM AUTO_INCREMENT=6394 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

编辑 SELECT 十六进制 (post_title)

real title is "gegužės 9, 2016 @ 10:16 PM"
post_title = gegužės 9, 2016 @ 10:16 PM
HEX(post_title) = 4F7264657220266E646173683B2067656775C385C2BEC384E280947320392C203230313620402031303A313620504D

可能的答案:

生成的INSERT是从mysqldump输出的?而且它不包括选项 --default-character-set=utf8?

(我认为,没有证据,这导致了问题。)

你现在有一个 table 有一些 'correct' 个字母和一些 "Mojibake"(例如 Ä„)吗?您想查找并修复 Mojibaked 行吗?

WHERE col LIKE '%Ä%' 可能会找到它。然而,TomÄ—nas不遵循相同的模式,所以我担心它不够。

我不知道如何解开 Ä— -- 可能需要两步甚至三步。

utf8 或 utf8mb4 之前的 table 是什么 CHARACTER SET?通常 Mojibake 涉及一些其他字符集(例如 latin1)和 utf8 之间的错误转换。我尝试了 latin2、latin5 和 latin7; none 似乎有效。

请提供我要求的SELECTs

我不会放弃,但这是一个很大的挑战。

可能的修复

(我说 "possible" 因为这可能是也可能不是完整和正确的答案。)

首先,测试一下:

SELECT ID,
        CONVERT(BINARY(CONVERT(post_title USING latin1)) USING utf8)
    FROM wp_posts;

查看它是否适用于所有行的 post_title。如果你喜欢输出,那么...

UPDATE wp_posts
    SET post_title =
        CONVERT(BINARY(CONVERT(post_title USING latin1)) USING utf8)

证据:

mysql> SELECT CONVERT(BINARY(CONVERT('gegužės 9, 2016 @ 10:16 PM' USING latin1)) USING utf8);
+---------------------------------------------------------------------------------------+
| CONVERT(BINARY(CONVERT('gegužės 9, 2016 @ 10:16 PM' USING latin1)) USING utf8)      |
+---------------------------------------------------------------------------------------+
| gegužės 9, 2016 @ 10:16 PM                                                            |
+---------------------------------------------------------------------------------------+