1 问题描述
在调用一个MySQL存储过程的时候,有时候会出现下面的错误:
Illigal mix of collations(gbk\_chinese\_ci, IMPLICIT) and (latin1\_swedish\_ci, IMPLICIT) for operation '='
我从去年到现在遇到了很多这个问题,这篇文章做一下解决方法的总结,基本上能覆盖这个问题的所有解法
2 问题根源
这个问题的出现是由于JOIN操作时=操作符的左右参数的字符编码不一致导致导致的,解决问题的方法也基于此
3 问题解法
存储过程的代码千奇百怪,导致这个问题的原因也有多种多样。下面就由浅入深地谈谈这个问题的解法
3.1 step1
遇到这个问题首先要做的,就是要查看存储过程中JOIN操作的两列的字符编码是否一致,如果其中一个是GBK,另一个是UTF8,那就要统一这两列的字符编码,具体修改成哪个, 看你的应用场景,一般情况下,建议使用UTF8,GBK更容易被SQL攻击,没有中文的数据时,就不要使用GBK了。
3.2 step2
如果step1修改后还是不能解决上面的问题,那您就需要查看一下您的存储过程中是否有where条件,很可能是您的where条件中=左右两侧的数据编码不一致,通过 show variables like '%character%' 命令查看client的编码是否跟database的编码一致。
+--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | gbk | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | gbk | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+
3.3 step3
上面的调整基本上能解决大部分此类问题,但是我们的存储过程依然执行不了。经过一番分析,发现我们的存储过程中会新建一个临时表,代码大概是这样:
INSERT INTO tmp(region, cell, relation) SELECT DISTINCT r.region, t.cell, -1 FROM rr_tmp r LEFT JOIN ( SELECT DISTINCT region, cell FROM ri_tmp ri, ce_tmp ct WHERE ri.region=ce.region) t ON r.region=t.region WHERE r.region is null;
我们怀疑字符编码不一致的原因是这个临时表的字符编码与rr_tmp表的字符编码不一致导致的,但是如何控制临时表的字符编码呢?
临时表的字符编码其实就是数据库的默认字符编码,通过 show create database test_db
可以看到数据库的字符编码 将数据库的字符编码修改成与rr_tmp的字符编码一致,就OK了
alter database test_db characeter set utf8
Date: 2015-02-04T15:58+0800