操作 'case' 的排序规则 (utf8_general_ci,COERCIBLE) 和 (latin1_swedish_ci,IMPLICIT) 的非法混合

Illegal mix of collations (utf8_general_ci,COERCIBLE) and (latin1_swedish_ci,IMPLICIT) for operation 'case'

我在 MySQL SERVER 5.5 和 MySQL SERVER 5.0 版本中使用两个 MySQL 服务器。我尝试在两个服务器中执行查询。这是我的查询:

DELIMITER $$

DROP PROCEDURE IF EXISTS `get_user_permissionlist`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `get_user_permissionlist`(
 pUserId INT,
 pApplicationId INT
)
BEGIN
DECLARE vDefaultManagerPermission VARCHAR(20);
SET vDefaultManagerPermission = (SELECT PermissionName FROM permission_level WHERE userid = pUserId);
IF vDefaultManagerPermission = 'Administrator'
THEN
    SELECT  PermissionId
           ,PermissionName
    FROM    ( SELECT    pl.PermissionId
               ,pl.PermissionName
               ,CASE permissionname
                  WHEN 'administrator' THEN '1'
                  WHEN 'operator' THEN '2'
                  WHEN 'power user' THEN '3'
                  ELSE '4'
                END AS rank
          FROM      permission_level pl
          WHERE     pl.ApplicationId = pApplicationId
        ) d
    ORDER BY CASE WHEN rank <= 3 THEN rank
              ELSE PermissionName
         END;
END IF;

END $$

DELIMITER ;

我尝试使用以下查询执行过程。

CALL st_proc_get_user_permissionlist('5', '1')

当我在MySQL SERVER 5.0 中执行查询时,没有问题。但我在 MySQL SERVER 5.5 中尝试了同样的操作,它显示错误:

Illegal mix of collations (utf8_general_ci,COERCIBLE) and (latin1_swedish_ci,IMPLICIT) for operation 'case'

我不明白为什么它会抛出错误,而且两个服务器的字符集、排序规则都相同。

可能您开始时在两台服务器上使用了不同的默认 排序规则。我们从两个方向调试一​​下。

  • 当 运行 查询时,从同一个连接执行 SHOW VARIABLES LIKE 'char%';。这可能会检查查询中文字的 "character set"。
  • SHOW CREATE TABLE 每台服务器上的每个 table。这应该确定字段的字符集,例如 PermissionName.

查看 bug 41627 是否适用,尽管它在 5.1.34 中是 'fixed'。

不涉及 VIEW,对吗?

这真的很奇怪:

ORDER BY 
        CASE WHEN rank <= 3 THEN rank
              ELSE PermissionName
         END;

rank设置为字符串12等,然后对比数字“3”,最后用PermissionName排序,这好像成为字符串。我不知道这是否是导致麻烦的 CASE,但我建议(为了我的理智)你不要混合数字和字符串。

你可以摆脱另一个案例:

WHERE PermissionName = CASE WHEN ApplicationId = 4
           THEN 'administrator'
           ELSE PermissionName END

重写为

WHERE ( PermissionName = 'administrator' OR ApplicationId != 4 ) 

编辑

由于数值组合比较奇怪,请尝试

ORDER BY CASE WHEN 0+rank <= 3 THEN CONCAT(_utf8 '', rank)
          ELSE CONVERT(PermissionName USING utf8)
     END;