不同字符集(utf8mb4_unicode_ci,EXPLICIT)和(utf8_general_ci,COERCIBLE)之间的非法混合,用于操作符'='。

28

好的,我放弃了。我已经陷入这个错误两天了,需要帮助。

免责声明:我需要帮助改进这个问题,并尽力描述问题的关键、我已经采取的解决问题的措施以及我搜索解决方案时阅读的博客文章和文档。

问题(也在下文中提出):

所以问题是,为什么相同的查询在从Rails而不是从mysql命令行运行时表现不同?具体来说,“(utf8_general_ci,COERCIBLE)”从何而来?

问题描述:Autoresponder.find_by(keyword: '')会失败并显示以下错误:

ActiveRecord::StatementInvalid: Mysql2::Error: Illegal mix of collations 
(utf8mb4_unicode_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) 
for operation '=': 
SELECT  `autoresponders`.* 
FROM `autoresponders`  
WHERE `autoresponders`.`keyword` = '' 
LIMIT 1

自动回复器是一个具有属性关键字的模型。

我读到需要指定我的排序规则。所以我尝试了以下代码:

Autoresponder.where('keyword collate utf8mb4_unicode_ci = ?', '')

并收到以下错误:

Illegal mix of collations 
(utf8mb4_unicode_ci,EXPLICIT) and (utf8_general_ci,COERCIBLE) 
for operation '=': 
SELECT `autoresponders`.* 
FROM `autoresponders`  
WHERE (keyword collate utf8mb4_unicode_ci = '')

那只是将排序规则从IMPLICIT更改为EXPLICIT。

我尝试在Sequel Pro中运行查询,它可以正常工作(使用或不使用collate关键字都可以)。为了清晰起见,这是查询:

SELECT `autoresponders`.* 
FROM `autoresponders`  
WHERE (keyword collate utf8mb4_unicode_ci = '');

SELECT `autoresponders`.* 
FROM `autoresponders`  
WHERE (keyword = ' ');

而且它还起作用!查询运行时没有出现错误。我也运行了mysql,并能够在那里运行查询。但是当我将查询粘贴到mysql命令行中时,我注意到了一些问题。它自动使用字符的Unicode名称,而不是实际字符。以下是在mysql命令行中观察到的查询:

SELECT `autoresponders`.* 
FROM `autoresponders`  
WHERE (keyword collate utf8mb4_unicode_ci ='\U+1F615');

这个查询有效。

问题是,为什么相同的查询在Rails中失败而在Sequel Pro中正常工作?具体来说,“(utf8_general_ci,COERCIBLE)”从哪里来,我该如何解决这个问题?

我认为它可能来自ActiveRecord,但在Rails控制台中运行 ActiveRecord :: Base.connection.collation 返回 utf8mb4_unicode_ci

这是我的数据库字符编码和排序变量(以及检索它们的查询)。

SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
character_set_client        utf8mb4
character_set_connection    utf8mb4
character_set_database      utf8mb4
character_set_filesystem    binary
character_set_results       utf8mb4
character_set_server        latin1
character_set_system        utf8
collation_connection        utf8mb4_unicode_ci
collation_database          utf8mb4_unicode_ci
collation_server            latin1_swedish_ci

以下是自动回复表的创建语法:

CREATE TABLE `autoresponders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `keyword` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT '',
  `body` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `provisioned_number_id` int(11) DEFAULT NULL,
  `outgoing_provisioned_number_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;

背景: Rails 4.0.13,Mysql版本5.6.22-1+deb.sury.org〜precise + 1-log

这里是我迄今为止阅读过的一些博客文章和SO文章:

https://mathiasbynens.be/notes/mysql-utf8mb4 http://airbladesoftware.com/notes/fixing-mysql-illegal-mix-of-collations/ “SET CHARACTER SET utf8”是否必要? 使用(utf8_unicode_ci,IMPLICIT)和(utf8_general_ci,IMPLICIT)进行操作时出现了字符集混合错误。 Active Record中不区分大小写搜索 https://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_collation_server

所有这些都促使我创建了这个梗:

enter image description here

真诚地,

一位筋疲力尽的开发人员。

谢谢。


2
错误信息表明MySQL声称客户端将''作为utf8字符输入。(应该声称为utf8mb4。)我不知道Ruby和ActiveRecord的细节,但那是我会查看的地方。 - Rick James
谢谢你的回复。我暂时停止了解决这个问题的工作,可能会在几周后回来处理它。如果我最终找到答案,我会在这里记录下来。奇怪的是,它现在在开发环境(OS X)中运行正常,但在预发布环境(Ubuntu)中不行。 - Jared Menard
我最终通过使用二进制大对象(blob)而不是文本来“修复”了这个问题。 - Jared Menard
1
另外,我们现在使用的是Postgres,它原生支持4字节字符。 - Jared Menard
5个回答

21

我遇到了类似的问题,最终解决了。 首先,我的MySQL配置是:

character-set-server = utf8
collation-server     = utf8_general_ci

有一天,我发现只有使用utf8mb4字符集才能正确保存表情符号,所以我像这样更改了指定列的字符集和排序规则:

  `nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,

到目前为止,一切都还好,数据可以被Java Web应用程序正确地保存和显示。

但是当我查询数据时,

SELECT * FROM table_name WHERE nickname LIKE '%%';

错误抛出。

最后我更改了mysql配置为

character-set-server = utf8mb4
collation-server     = utf8mb4_unicode_ci

一切都很顺利。

还要确保删除或替换任何对SET NAMES utf8;的调用,改为SET NAMES utf8mb4

这里是MySQL客户端的屏幕截图,请注意“nickname”属性


如果您有一个Ruby on Rails应用程序,您可以通过在database.yml中添加以下内容来更改配置:charset: utf8mb4 collation: utf8mb4_unicode_ci``` 请确保它在3行内(stackoverflow会打断行)。 - ajimix
请展示整个文件。 - Florent

8

我遇到了相同的错误,我在where语句后添加了collate。

SELECT *  FROM chat_words where source ='forum';

抛出了“不合法的字符集组合 (utf8mb4_unicode_ci, COERCIBLE) 和 (utf8mb4_general_ci, COERCIBLE)” 的错误,用于操作符号“=”。

后来我进行了更改:

SELECT *  FROM chat_words where source collate utf8mb4_unicode_ci ='forum';

这个运行没有出现错误。

1

当我将我的数据库复制到其他服务器时,我遇到了相同的问题。我已经将我的排序规则更改为utf8mb4_general_ci,现在看起来一切都正常。


1

我已经从phpMyAdmin解决了这个问题,方法是将列的排序规则更改为utf8mb4_unicode_ci


1
如果您能描述一下您所做的事情,那将非常棒。 - wedi

1

我现在遇到了同样的问题,并发现Debian在配置文件中修复了排序规则(/etc/mysql/mariadb.conf.d/50-server.cnf)

# MySQL/MariaDB default is Latin1, but in Debian we rather default to the full
# utf8 4-byte character set. See also client.cnf
character-set-server  = utf8mb4
collation-server      = utf8mb4_general_ci

在这里更改排序规则后,问题已经解决。

感谢您的回答,欢迎来到 Stack Overflow! - Jared Menard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接