【问题标题】:Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '='用于操作“=”的排序规则 (utf8_unicode_ci,IMPLICIT) 和 (utf8_general_ci,IMPLICIT) 的非法混合
【发布时间】:2012-07-30 23:43:05
【问题描述】:

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 时也会出现同样的错误。 我还测试过重新创建整个数据库,但效果不佳。

任何帮助将不胜感激。

【问题讨论】:

  • 我在尝试加入 3 个表的记录时遇到了同样的问题。当我检查我的数据库时,我发现其中一个表有 utf8_general,但其他表有 utf8_unicode_ci。所以我将 utf8_general 更改为 utf8_unicode_ci 并且我的问题解决了。

标签: mysql stored-procedures


【解决方案1】:

存储过程参数的默认排序规则是utf8_general_ci,你不能混合排序规则,所以你有四种选择:

选项 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 参数定义中(MySQL 5.7 之前):

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;

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

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

【讨论】:

  • 还可以将COLLATE utf8_unicode_ci 添加到字符串常量:SET @EMAIL = 'abc@def.com' COLLATE utf8_unicode_ci;。如果您从控制台运行脚本,则它特别有用,其中控制台默认编码适用于字符串常量的排序规则。
  • 或删除数据库并使用 utf8_general_ci 创建新数据库;排序规则。
  • 为了将来参考,除非您了解两种排序规则之间的区别,否则不要将所有表都更改为 utf8_general_ci。
  • @GaborSch 将排序规则添加到字符串变量是我的解决方案,在我注意到您的评论之前,我写了一个详细的答案。
  • 我遇到了同样的错误,除了(utf8mb4_unicode_ci, IMPLICIT) 而不是(utf8_unicode_ci, IMPLICIT)。我正在使用 python 从网络上抓取数据,然后使用抓取的数据创建一个 CSV 文件,然后我使用服务器上的 PHP 文件处理该文件,该文件将数据上传到我的数据库。我所有的 MySQL 表/列都整理为utf8mb4_unicode_ci。是否会出现问题,因为我在 python/csv 中将数据编码为utf8
【解决方案2】:

我花了半天时间寻找相同的“Illegal mix of collat​​ions”错误的答案,其中 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;

这解决了我的“非法混合排序规则”错误。希望这可能对其他人有所帮助。

【讨论】:

  • 谢谢。 “SHOW CREATE TABLE”是了解和解决问题根本原因的最简单方法。
  • 另请注意,为整个表指定COLLATE(即ALTER TABLE table1 CHARSET utf8 COLLATE utf8_unicode_ci不会解决问题,必须为每个(有问题的)列执行此操作.
  • @SkippyleGrandGourou 我删除了表并使用 CHARSET utf8 COLLATE utf8_unicode_ci 重新创建了它,它对我有用。
  • @veritas 是的,我的评论是关于更改表格,而不是从头开始重新创建。
  • 此外,无论出于何种原因,mysql bench 都会对字段和表的值有误导性的答案。使用上述手动更改语句是确保它也为我正确设置的唯一方法。
【解决方案3】:

我遇到了类似的问题,但是当我的查询参数使用变量设置时,我在程序内部发生了这种情况,例如SET @value='foo'.

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

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

【讨论】:

  • 同样的问题发生在我身上,我通过直接在变量声明中设置排序规则来避免更改 collat​​ion_YYY 变量。 SET @my_var = 'string1,string2' COLLATE utf8_unicode_ci;
【解决方案4】:

有点类似于@bpile 的回答,我的案例是一个my.cnf 入口设置collation-server = utf8_general_ci。在我意识到这一点之后(并且在尝试了上述所有操作之后),我强行将我的数据库切换到 utf8_general_ci 而不是 utf8_unicode_ci 就是这样:

ALTER DATABASE `db` CHARACTER SET utf8 COLLATE utf8_general_ci;

【讨论】:

  • 奇怪的是,配置分布如此之多。所有排序规则默认值都应该设置在同一个地方。
【解决方案5】:

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

ALTER DATABASE databasename CHARACTER SET utf8 COLLATE utf8_unicode_ci;

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

solution的来源

【讨论】:

    【解决方案6】:

    在我自己的情况下,我有以下错误

    用于操作“=”的排序规则 (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) as fullname") ->join('users', 'users.username=classroom_students.matric_no', 'left') ->where('classroom_students.session_id', $session) ->where('classroom_students.level_id', $level) ->where('classroom_students.dept_id', $dept);

    经过数周的谷歌搜索后,我注意到我正在比较的两个字段包含不同的排序规则名称。第一个,即用户名是 utf8_general_ci,而第二个是 utf8_unicode_ci,所以我回到第二个表的结构并将第二个字段(matric_no)更改为 utf8_general_ci,它就像一个魅力。

    【讨论】:

      【解决方案7】:

      尽管发现了大量关于同一问题的问题(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')
      ;
      

      在我原来的例子中,我有更多的连接。 当然,table1 和 table2 有不同的排序规则。 使用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;
      

      【讨论】:

      【解决方案8】:

      当一列显式设置为不同的排序规则或查询的表中的默认排序规则不同时,就会发生这种情况。

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

      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;
      

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

      【讨论】:

      • 当(在我的情况下)您的 SP 的默认排序规则与用于查询的表的排序规则不同时,也会发生这种情况。
      猜你喜欢
      • 2010-11-03
      • 2020-04-15
      • 2016-02-19
      • 1970-01-01
      • 1970-01-01
      • 2018-01-19
      • 2023-03-21
      • 2017-10-17
      • 1970-01-01
      相关资源
      最近更新 更多