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

Man*_*tax 142 mysql stored-procedures

MySql上的错误消息:

Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

任何帮助都感激不尽.

Ros*_* II 204

有四种选择:

选项1:添加utf8_general_ci到输入变量:

SET @rUsername = ‘aname’ COLLATE utf8_unicode_ci; -- COLLATE added
CALL updateProductUsers(@rUsername, @rProductID, @rPerm);
Run Code Online (Sandbox Code Playgroud)

选项2:添加COLLATECOLLATE条款中:

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

选项4:改变场地本身:

ALTER TABLE users CHARACTER SET utf8 COLLATE utf8_general_ci;
Run Code Online (Sandbox Code Playgroud)

作为存储过程参数的默认排序规则IN,您不能混合排序规则.

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

更新:utf8mb4/utf8mb4_unicode_ci现在是首选的字符集/整理方法.建议不要使用utf8_general_ci,因为性能提升可以忽略不计.请参阅/sf/answers/53689751/

  • 还可以将 `COLLATE utf8_unicode_ci` 添加到字符串常量:`SET @EMAIL = 'abc@def.com' COLLATE utf8_unicode_ci;`。如果您从控制台运行脚本,其中控制台默认编码适用于字符串常量的排序规则,则它特别有用。 (2认同)
  • 为了将来参考,除非您了解两个排序规则之间的差异,否则不要将所有表更改为utf8_general_ci. (2认同)
  • @GaborSch 将整理添加到字符串变量对我来说是解决方案,在注意到您的评论之前我写了一个详细的答案。 (2认同)

Nat*_*han 24

我花了半天的时间在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 |
Run Code Online (Sandbox Code Playgroud)

注意'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;

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

  • 谢谢.'SHOW CREATE TABLE'是理解和解决问题根本原因的最简单方法. (5认同)
  • 另请注意,为整个表指定“COLLATE”(即“ALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci”)**不会解决问题**,必须为每个(有问题的)列指定“COLLATE”。 (2认同)

bpi*_*ile 5

我有一个类似的问题,但它在我的内部程序中发生,当我的查询参数设置使用变量例如SET @value='foo'.

造成这种情况的原因是不匹配collation_connection和数据库整理.改为collation_connection匹配collation_database,问题消失了.我认为这比在param/value之后添加COLLATE更优雅.

总结:所有排序规则必须匹配.使用SHOW VARIABLES并确保collation_connectioncollation_database匹配(也使用检查表核对SHOW TABLE STATUS [table_name]).


Seb*_*bas 5

有点类似于@bpil 答案,我的情况是 my.cnf 条目设置collation-server = utf8_general_ci。在我意识到这一点之后(并在尝试了上述所有内容之后),我强行将我的数据库切换到 utf8_general_ci 而不是 utf8_unicode_ci,就是这样:

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;
Run Code Online (Sandbox Code Playgroud)