操作'='的非法混合排序(utf8_unicode_ci,IMPLICIT)和(utf8_general_ci,IMPLICIT)

时间:2012-08-02 02:05:04

标签: mysql stored-procedures

MySql上的错误消息:

Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='

我已经浏览了其他几个帖子,但无法解决此问题。 受影响的部分与此类似:

CREATE TABLE users (
    userID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    firstName VARCHAR(24) NOT NULL,
    lastName VARCHAR(24) NOT NULL,
    username VARCHAR(24) NOT NULL,
    password VARCHAR(40) NOT NULL,
    PRIMARY KEY (userid)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE products (
    productID INT UNSIGNED NOT NULL AUTO_INCREMENT,
    title VARCHAR(104) NOT NULL,
    picturePath VARCHAR(104) NULL,
    pictureThumb VARCHAR(104) NULL,
    creationDate DATE NOT NULL,
    closeDate DATE NULL,
    deleteDate DATE NULL,
    varPath VARCHAR(104) NULL,
    isPublic TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
    PRIMARY KEY (productID)
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE productUsers (
    productID INT UNSIGNED NOT NULL,
    userID INT UNSIGNED NOT NULL,
    permission VARCHAR(16) NOT NULL,
    PRIMARY KEY (productID,userID),
    FOREIGN KEY (productID) REFERENCES products (productID) ON DELETE RESTRICT ON UPDATE NO ACTION,
    FOREIGN KEY (userID) REFERENCES users (userID) ON DELETE RESTRICT ON UPDATE NO ACTION
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

我正在使用的存储过程是:

CREATE PROCEDURE updateProductUsers (IN rUsername VARCHAR(24),IN rProductID INT UNSIGNED,IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername
        AND productUsers.productID = rProductID;
END

我正在使用php进行测试,但SQLyog也出现了同样的错误。 我也测试过重新创建整个数据库,但没有好处。

非常感谢任何帮助。

8 个答案:

答案 0 :(得分:183)

有四种选择:

选项1 :将COLLATE添加到输入变量中:

SET @rUsername = ‘aname’ COLLATE utf8_unicode_ci; -- COLLATE added
CALL updateProductUsers(@rUsername, @rProductID, @rPerm);

选项2 :将COLLATE添加到WHERE子句:

CREATE PROCEDURE updateProductUsers(
    IN rUsername VARCHAR(24),
    IN rProductID INT UNSIGNED,
    IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername COLLATE utf8_unicode_ci -- COLLATE added
        AND productUsers.productID = rProductID;
END

选项3 :将其添加到IN参数定义:

CREATE PROCEDURE updateProductUsers(
    IN rUsername VARCHAR(24) COLLATE utf8_unicode_ci, -- COLLATE added
    IN rProductID INT UNSIGNED,
    IN rPerm VARCHAR(16))
BEGIN
    UPDATE productUsers
        INNER JOIN users
        ON productUsers.userID = users.userID
        SET productUsers.permission = rPerm
        WHERE users.username = rUsername
        AND productUsers.productID = rProductID;
END

选项4 :改变字段本身:

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;

由于存储过程参数的默认排序规则为utf8_general_ci,因此您无法混合排序规则。

除非您需要按Unicode顺序对数据进行排序,否则我建议您更改所有表以使用utf8_general_ci排序规则,因为它不需要更改代码,并且会稍微加快排序。

UPDATE :utf8mb4 / utf8mb4_unicode_ci现在是首选的字符集/整理方法。建议不要使用utf8_general_ci,因为性能提升可以忽略不计。见https://stackoverflow.com/a/766996/1432614

答案 1 :(得分:20)

我花了半天时间搜索相同的“非法混合排序”错误以及utf8_unicode_ci和utf8_general_ci之间的冲突。

我发现我的数据库中的某些列没有专门整理 utf8_unicode_ci 。似乎mysql隐式整理了这些列 utf8_general_ci

具体来说,运行'SHOW CREATE TABLE table1'查询输出如下内容:

| table1 | CREATE TABLE `table1` (
`id` int(11) NOT NULL,
`col1` varchar(4) CHARACTER SET utf8 NOT NULL,
`col2` int(11) NOT NULL,
PRIMARY KEY (`col1`,`col2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

注意行'col1'varchar(4)CHARACTER SET utf8 NOT NULL 没有指定排序规则。然后我运行了以下查询:

ALTER TABLE table1 CHANGE col1 col1 VARCHAR(4) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;

这解决了我的“非法混合排序”错误。希望这可以帮助其他人。

答案 2 :(得分:5)

我遇到了类似的问题,但是当我的查询参数设置为使用变量时,我在内部程序中遇到了问题。 SET @value='foo'

造成这种情况的原因是collation_connection和数据库排序规则不匹配。已更改collation_connection以匹配collation_database,问题就消失了。我认为这比在param / value之后添加COLLATE更优雅。

总结:所有排序规则必须匹配。使用SHOW VARIABLES并确保collation_connectioncollation_database匹配(同时使用SHOW TABLE STATUS [table_name]检查表格整理)。

答案 3 :(得分:4)

有点类似于@bpile的答案,我的案例是my.cnf条目设置.StrikeCSS { text-decoration: line-through !important; color : BLACK !important; } 。在我意识到这一点之后(以及在尝试了上述所有内容之后),我强行将我的数据库切换为utf8_general_ci而不是utf8_unicode_ci,就是这样:

collation-server = utf8_general_ci

答案 4 :(得分:0)

我个人有以下错误

操作'='的归类(utf8_general_ci,IMPLICIT)和(utf8_unicode_ci,IMPLICIT)的非法混合

  

$ this-> db-> select(“ users.username as matric_no,CONCAT(users.surname,   ''           users.first_name,“',users.last_name)作为全名”)           ->加入('users','users.username = classroom_students.matric_no','left')           ->其中('classroom_students.session_id',$ session)           ->其中('classroom_students.level_id',$ level)           ->其中('classroom_students.dept_id',$ dept);

经过数周的Google搜索,我注意到我正在比较的两个字段由不同的归类名称组成。第一个用户名即utf8_general_ci,而第二个用户名则为utf8_unicode_ci,因此我返回第二个表的结构,并将第二个字段(matric_no)更改为utf8_general_ci,它像一个魅力一样工作。

答案 5 :(得分:0)

尽管找到了大量有关同一问题的问题(1234),但我从未找到将性能考虑在内的答案,即使在这里。

尽管已经给出了多种可行的解决方案,但我还是要考虑性能。

编辑:感谢Manatax指出选项1不会遇到性能问题。

使用选项 1和 2 ,也就是 COLLATE 强制转换方法,可能会导致瓶颈,导致列上定义的任何索引都会不会导致全面扫描

即使我没有尝试选项3 ,但我的直觉是,它将遭受选项 1和 2的相同后果。

最后,对于可行的大型表,选项4 是最佳选择。我的意思是,没有其他依赖原始排序规则的用法。

考虑以下简化查询:

SELECT 
    *
FROM
    schema1.table1 AS T1
        LEFT JOIN
    schema2.table2 AS T2 ON T2.CUI = T1.CUI
WHERE
    T1.cui IN ('C0271662' , 'C2919021')
;

在我的原始示例中,我有更多的联接。 当然,表1和表2具有不同的排序规则。 使用 collat​​e 运算符进行强制转换,将导致索引不被使用。

请参见下图中的sql说明。

Visual Query Explanation when using the COLLATE cast

另一方面,选项4 可以利用可能的索引并带来快速查询。

在下面的图片中,您可以看到在应用选项4 后又运行了相同的查询,也就是更改了架构/表/列的排序规则。

Visual Query Explanation after the collation has been changed, and therefore without the collate cast

最后,如果性能很重要,并且您可以更改表格的排序规则,请使用选项4 。 如果您必须对单个列执行操作,则可以使用以下内容:

ALTER TABLE schema1.table1 MODIFY `field` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

答案 6 :(得分:0)

在将列显式设置为其他排序规则或查询的表中默认排序规则不同的情况下,会发生这种情况。

如果您有很多表,则要在运行此查询时更改排序规则:

select concat('ALTER TABLE ', t.table_name , ' CONVERT TO CHARACTER 
SET utf8 COLLATE utf8_unicode_ci;') from (SELECT table_name FROM 
information_schema.tables where table_schema='SCHRMA') t;

这将输出转换所有表以使用每列正确的排序规则所需的查询

答案 7 :(得分:0)

答案正在添加到@Sebas的答案-设置我的本地环境的排序规则。请勿在生产中尝试使用。

ALTER DATABASE databasename CHARACTER SET utf8 COLLATE utf8_unicode_ci;

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

solution

的来源