尝试通过MySQL中的存储过程进行选择时出现以下错误。
操作'='的排序规则(latin1_general_cs,IMPLICIT)和(latin1_general_ci,IMPLICIT)的非法混合
您对这里可能出什么问题有任何想法吗?
表的排序规则是latin1_general_ci
and where子句中的列的排序规则latin1_general_cs
。
尝试通过MySQL中的存储过程进行选择时出现以下错误。
操作'='的排序规则(latin1_general_cs,IMPLICIT)和(latin1_general_ci,IMPLICIT)的非法混合
您对这里可能出什么问题有任何想法吗?
表的排序规则是latin1_general_ci
and where子句中的列的排序规则latin1_general_cs
。
Answers:
通常,这是通过比较两个不兼容的排序规则字符串或尝试将不同排序规则的数据选择到组合列中引起的。
该子句COLLATE
允许您指定查询中使用的排序规则。
例如,以下WHERE
子句将始终给出您发布的错误:
WHERE 'A' COLLATE latin1_general_ci = 'A' COLLATE latin1_general_cs
您的解决方案是为查询中的两列指定共享排序规则。这是使用COLLATE
子句的示例:
SELECT * FROM table ORDER BY key COLLATE latin1_general_ci;
另一种选择是使用BINARY
运算符:
BINARY str是CAST(str AS BINARY)的简写。
您的解决方案可能看起来像这样:
SELECT * FROM table WHERE BINARY a = BINARY b;
要么,
SELECT * FROM table ORDER BY BINARY a;
更改一个(或两个)字符串的排序规则以使它们匹配,或者COLLATE
在表达式中添加一个子句。
这到底是什么“整理”的东西?
甲字符集是一组符号和编码。甲归类为在一个字符集的字符进行比较的一组规则。让我们用一个假想字符集的例子来使区别清楚。
假设我们有一个包含四个字母的字母:“
A
”,“B
”,“a
”,“b
”。我们给每个字母一个数字:“A
” = 0,“B
” = 1,“a
” = 2,“b
” =3。字母“A
”是一个符号,数字0是“ ” 的编码A
,并且所有的组合四个字母及其编码是一个字符集。假设我们要比较两个字符串值“
A
”和“B
”。最简单的方法是查看编码:“A
”为0,“ ”为1B
。因为0小于1,所以我们说“A
”小于“B
”。我们刚才所做的是将排序规则应用于字符集。排序规则是一组规则(在这种情况下,只有一个规则):“比较编码”。我们将所有可能的排序规则中最简单的排序规则称为二进制排序规则。但是,如果我们想说小写字母和大写字母是等效的呢?然后,我们将至少有两个规则:(1)将小写字母“
a
”和“b
”等同于“A
”和“B
”;(2)然后比较编码。我们称此为不区分大小写的排序规则。它比二进制排序规则要复杂一些。在现实生活中,大多数字符集都有许多字符:不仅是“
A
”和“B
”,还包括整个字母,有时甚至是多个字母或带有数千个字符的东方书写系统,以及许多特殊符号和标点符号。同样在现实生活中,大多数归类都有很多规则,不仅用于区分字母大小写,而且还用于区分是否区分重音(“重音”是附加在字符上的标记,如德语中的“Ö
”),以及用于多个字符映射(例如两个德国归类之一中的“Ö
” =“OE
” 的规则)。
在“整理效果的示例”下给出了更多示例。
好的,但是MySQL如何确定给定表达式使用哪种排序规则?
在绝大多数语句中,很明显MySQL使用什么排序规则来解决比较操作。例如,在以下情况下,应该清楚排序规则是column的排序规则
charset_name
:SELECT x FROM T ORDER BY x; SELECT x FROM T WHERE x = x; SELECT DISTINCT x FROM T;
但是,对于多个操作数,可能会有歧义。例如:
SELECT x FROM T WHERE x = 'Y';
比较应该使用列的排序规则
x
还是字符串文字的排序规则'Y'
?双方x
并'Y'
有排序规则,所以其整理的优先级?标准SQL使用以前称为“强制性”规则的方式解决了此类问题。
[ 删除 ]MySQL使用强制性值和以下规则来解决歧义:
使用具有最低矫顽力值的排序规则。
如果双方具有相同的强制性,则:
如果双方都是Unicode,或者双方都不是Unicode,则错误。
如果其中一方具有Unicode字符集,而另一方具有非Unicode字符集,则以具有Unicode字符集的一方为准,并且自动字符集转换将应用于非Unicode一方。例如,以下语句不返回错误:
SELECT CONCAT(utf8_column, latin1_column) FROM t1;
它返回一个结果,该结果的字符集为
utf8
,排序规则与相同utf8_column
。的值latin1_column
会utf8
在连接前自动转换为。对于具有相同字符集但混合使用
_bin
归类和a_ci
或_cs
归类的操作数的运算,将使用归类_bin
。这类似于混合非二进制字符串和二进制字符串的操作如何将操作数评估为二进制字符串,不同之处在于它用于排序规则而不是数据类型。
那么什么是“非法归类”?
当表达式比较两个不同归类但具有相同强制性的字符串并且强制性规则无法帮助解决冲突时,就会发生“非法归类”。这是上述引用中第三个要点下描述的情况。
问题中给出的特定错误Illegal mix of collations (latin1_general_cs,IMPLICIT) and (latin1_general_ci,IMPLICIT) for operation '='
告诉我们,两个具有相同可强制性的非Unicode字符串之间存在相等比较。它进一步告诉我们,排序规则不是在语句中显式给出的,而是从字符串的源(例如列元数据)中隐含的。
一切都很好,但是如何解决这种错误呢?
正如上面引述的手册摘录所暗示的,可以通过多种方式解决此问题,其中两种是明智的,并建议使用:
更改一个(或两个)字符串的排序规则,使它们匹配,并且不再存在歧义。
如何完成此操作取决于字符串的来源:文字表达式采用collation_connection
系统变量中指定的排序规则;表中的值采用其列元数据中指定的排序规则。
强制一个字符串不可强制。
我从上面省略了以下引文:
MySQL分配强制性值如下:
因此,简单地COLLATE
在比较中使用的字符串之一中添加一个子句将强制使用该排序规则。
尽管如果将其他部署仅用于解决此错误,则将是非常糟糕的做法:
强制其中一个(或两个)字符串具有其他强制性值,以使一个优先。
使用CONCAT()
或CONCAT_WS()
会导致矫顽力为1的字符串;(如果在存储的例程中)使用参数/局部变量将导致字符串的强制性为2。
更改一个(或两个)字符串的编码,以使一个是Unicode,而另一个不是。
这可以通过使用; 进行转码来完成。或通过更改数据的基础字符集(例如,修改列,更改文字值或以不同的编码从客户端发送它们以及更改/添加字符集介绍程序)。请注意,如果某些所需字符无法在新字符集中进行编码,则更改编码会导致其他问题。CONVERT(expr USING transcoding_name)
character_set_connection
character_set_client
更改一个(或两个)字符串的编码,以使它们都相同,并更改一个字符串以使用相关的_bin
排序规则。
上面已经详细描述了改变编码和排序规则的方法。如果一个人实际上需要应用比归类所提供的更高级的归类规则,那么这种方法将几乎没有用_bin
。
我正在调查一个类似的问题,在使用接收到varchar参数的自定义函数时出现以下错误:
Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and
(utf8_general_ci,IMPLICIT) for operation '='
使用以下查询:
mysql> show variables like "collation_database";
+--------------------+-----------------+
| Variable_name | Value |
+--------------------+-----------------+
| collation_database | utf8_general_ci |
+--------------------+-----------------+
我能够告诉数据库使用utf8_general_ci,而表是使用utf8_unicode_ci定义的:
mysql> show table status;
+--------------+-----------------+
| Name | Collation |
+--------------+-----------------+
| my_view | NULL |
| my_table | utf8_unicode_ci |
...
请注意,视图具有NULL排序规则。似乎该视图和函数具有排序规则定义,即使此查询显示一个视图为null。使用的排序规则是在创建视图/函数时定义的数据库排序规则。
可悲的解决方案是更改数据库排序规则并重新创建视图/函数以强制它们使用当前的排序规则。
更改数据库的排序规则:
ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
更改表排序规则:
ALTER TABLE mydb CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
我希望这会对某人有所帮助。
show full columns from my_table;
alter table <TABLE> modify column <COL> varchar(255) collate utf8_general_ci;
SHOW session variables like '%collation%';
告诉您»collation_connection«是»utf8mb4_general_ci«?然后SET collation_connection = utf8mb4_unicode_ci
事先运行。
我有一个类似的问题,试图将FIND_IN_SET过程与字符串变量一起使用。
SET @my_var = 'string1,string2';
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);
并收到错误
错误代码:1267。非法混合使用排序规则(utf8_unicode_ci,IMPLICIT)和(utf8_general_ci,IMPLICIT)操作'find_in_set'
简短答案:
无需更改任何collation_YYYY变量,只需在变量声明旁边添加正确的排序规则,即
SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
SELECT * from my_table WHERE FIND_IN_SET(column_name,@my_var);
长答案:
我首先检查了排序规则变量:
mysql> SHOW VARIABLES LIKE 'collation%';
+----------------------+-----------------+
| Variable_name | Value |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
+----------------------+-----------------+
| collation_database | utf8_general_ci |
+----------------------+-----------------+
| collation_server | utf8_general_ci |
+----------------------+-----------------+
然后我检查了表排序规则:
mysql> SHOW CREATE TABLE my_table;
CREATE TABLE `my_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`column_name` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=125 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
这意味着我的变量已配置为默认排序规则utf8_general_ci,而我的表已配置为utf8_unicode_ci。
通过在变量声明旁边添加COLLATE命令,变量归类与为表配置的归类匹配。
如果涉及文字,则为解决方案。
我正在使用Pentaho Data Integration,但未指定SQL语法。使用非常简单的数据库查找,出现错误“操作'='的排序规则(cp850_general_ci,COERCIBLE)和(latin1_swedish_ci,COERCIBLE)的排序规则非法混合”
生成的代码是“从hr_cc_normalised_data_date_v WHERE PSEUDO_KEY =吗?
简短地讲故事是为了查看,当我发布时
mysql> show full columns from hr_cc_normalised_data_date_v;
+------------+------------+-------------------+------+-----+
| Field | Type | Collation | Null | Key |
+------------+------------+-------------------+------+-----+
| PSEUDO_KEY | varchar(1) | cp850_general_ci | NO | |
| DATA_DATE | varchar(8) | latin1_general_cs | YES | |
+------------+------------+-------------------+------+-----+
解释了“ cp850_general_ci”的来源。
该视图只是使用'SELECT'X',...'创建的。根据这样的手册文字,应该从服务器设置继承它们的字符集和排序规则,服务器设置正确定义为'latin1'和'latin1_general_cs'显然没有发生,我在创建视图时强迫了它
CREATE OR REPLACE VIEW hr_cc_normalised_data_date_v AS
SELECT convert('X' using latin1) COLLATE latin1_general_cs AS PSEUDO_KEY
, DATA_DATE
FROM HR_COSTCENTRE_NORMALISED_mV
LIMIT 1;
现在,两列都显示latin1_general_cs,错误已消失。:)
MySQL确实不喜欢混合排序规则,除非它可以将它们强制为同一排序规则(在您的情况下这显然不可行)。您是否只能通过COLLATE子句强制使用相同的排序规则?(或BINARY
适用的更简单的快捷方式...)。
如果您遇到麻烦的列是“哈希”,请考虑以下内容...
如果“哈希”是二进制字符串,则应真正使用BINARY(...)
数据类型。
如果“哈希”是一个十六进制字符串,则不需要utf8,并且由于字符检查等原因应避免这种情况。例如,MySQL MD5(...)
产生固定长度的32字节十六进制字符串。 SHA1(...)
给出一个40字节的十六进制字符串。这可以存储到CHAR(32) CHARACTER SET ascii
(对于sha1,则存储为40)。
或者,最好将其存储UNHEX(MD5(...))
到中BINARY(16)
。这样可将色谱柱尺寸减小一半。(但是,它确实使它无法打印。) SELECT HEX(hash) ...
如果您希望它可读。
比较两BINARY
列没有排序规则问题。
非常有趣...现在,准备好。我查看了所有“添加整理”解决方案,对我来说,这些都是创可贴修复程序。现实情况是数据库设计很“糟糕”。是的,添加了标准更改和新内容,等等,但这并不会改变错误的数据库设计事实。我拒绝采用在整个SQL语句中添加“整理”的路线,只是为了使我的查询正常工作。唯一对我有用的解决方案,实际上消除了将来对代码进行调整的需要,是重新设计数据库/表,以匹配我将长期使用并使用的字符集。在这种情况下,我选择使用字符集“ utf8mb4 ”。
因此,遇到“非法”错误消息时,此处的解决方案是重新设计数据库和表。这听起来比以前容易得多,也更快。甚至不需要导出数据并从CSV重新导入数据。更改数据库的字符集,并确保表的所有字符集都匹配。
使用以下命令指导您:
SHOW VARIABLES LIKE "collation_database";
SHOW TABLE STATUS;
现在,如果您喜欢在各处添加“整理”,并用强制填充“覆盖”来增强代码,请问是我的猜测。
一种可能的解决方案是将整个数据库转换为UTF8(另请参见此问题)。
如果您安装了phpMyAdmin,则可以按照以下链接中给出的说明进行操作:https : //mediatemple.net/community/products/dv/204403914/default-mysql-character-set-and-collation您必须匹配排序规则数据库的所有表以及表的字段,然后重新编译所有存储过程和函数。这样,一切都应该再次工作。
我用过ALTER DATABASE mydb DEFAULT COLLATE utf8_unicode_ci;
,但是没用。
在此查询中:
Select * from table1, table2 where table1.field = date_format(table2.field,'%H');
这项工作对我来说:
Select * from table1, table2 where concat(table1.field) = date_format(table2.field,'%H');
是的,只有一个concat
。