MySQL隐含地强制查看错误的排序规则

问题描述 投票:6回答:3

在MySQL 5.6中,一个视图似乎隐含地将utf8_general_ci强制转换为latin1_swedish_ci而不是预期的latin1_general_cs

我的设置:

数据库变量:

mysql> show variables like 'col%';
+----------------------+-------------------+
| Variable_name        | Value             |
+----------------------+-------------------+
| collation_connection | latin1_general_cs |
| collation_database   | latin1_general_cs |
| collation_server     | latin1_general_cs |
+----------------------+-------------------+

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

这是我的数据库和表格:

CREATE DATABASE `example` /*!40100 DEFAULT CHARACTER SET latin1 COLLATE latin1_general_cs */;

CREATE TABLE `example` (
  `username` varchar(20) COLLATE latin1_general_cs NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs;

insert into example values ('user_a');

我的观点是:

create or replace view example_view as
select username
from example
where substring_index(user(), '@', 1) = example.username;

我的问题:

从该视图中选择时,我收到错误:

mysql> select * from example_view;
ERROR 1267 (HY000): Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (latin1_general_cs,IMPLICIT) for operation '='

当我直接运行select语句时,它可以工作。

据我所知,NOTHING将使用latin1_swedish_ci。服务器,数据库,表和列都设置为latin1_general_cs

以下是MySQL认为每个部分的排序规则:

mysql> select COLLATION(username) as username, 
    -> COLLATION(user()) as user_func, 
    -> COLLATION(substring_index(user(), '@', 1)) as substr_func
    -> from example;
+-------------------+-----------------+-----------------+
| username          | user_func       | substr_func     |
+-------------------+-----------------+-----------------+
| latin1_general_cs | utf8_general_ci | utf8_general_ci |
+-------------------+-----------------+-----------------+

所以MySQL试图从utf8_general_ci转换为匹配latin1_general_cs。但不知何故,在视图的上下文中,它决定使用latin1_swedish_ci代替。

我知道我可以使用convert(),但我想避免这种情况(部分是出于好奇,部分原因是因为大量的converts()会导致丑陋的查询)。

我的问题:

为什么MySQL转换为latin1_swedish_ci而不是latin1_general_cs?除了在查询中明确使用convert()之外,我该如何解决?

mysql collation
3个回答
3
投票

问:为什么MySQL转换为latin1_swedish_ci而不是latin1_general_cs

每个characterset都有一个默认排序规则。您可以使用SHOW COLLATION语句来查看此内容。输出的摘录显示latin1_swedish_cilatin1字符集的默认排序规则:

Collation             Charset       Id  Default  Compiled  Sortlen  
--------------------  --------  ------  -------  --------  ---------
latin1_german1_ci     latin1         5           Yes               1
latin1_swedish_ci     latin1         8  Yes      Yes               1
latin1_bin            latin1        47           Yes               1
latin1_general_ci     latin1        48           Yes               1
latin1_general_cs     latin1        49           Yes               1

我们已经知道每个表都有默认的字符集和默认排序规则。使用视图定义,MySQL实际上在查询运行时创建表。

在MySQL白话中,它被称为“派生表”。

(顺便说一句,MySQL确实允许使用ALGORITHM=MERGE而不是典型和熟悉的ALGORITHM=TEMPTABLE定义一些视图。使用MERGE算法,我们获得的视图处理行为更像是其他关系数据库的行为,如Oracle和SQL Server。)

当MySQL创建派生表时,它会分配一个字符集及其默认排序规则。

这就是latin1_swedish_ci来自的地方...... latin1的默认排序规则。


Q2:除了在查询中明确使用CONVERT()之外,我该如何解决这个问题?

您可以尝试在没有CONVERT()函数的情况下指定排序规则:

CREATE VIEW example_view
AS 
SELECT username COLLATE latin1_general_cs
FROM example
WHERE SUBSTRING_INDEX(USER(), '@', 1) COLLATE latin1_general_cs = example.username;

(如果您的客户端字符集是utf8,那么如果您还没有CONVERT(... USING ...),则可能会遇到该语法的错误。您可以将COLLATECONVERT()函数结合使用。

  CONVERT(USER() USING latin1) COLLATE latin1_general_cs

注意:我对存储的视图没有任何实际经验;我们在整个地方使用内联视图。但是我们永远不会创建存储的视图,因为存储的视图会导致无数的问题,比视图定义解决方案的任何问题都更大,问题更多。


1
投票

不确定您要求的是什么,但只是为了避免错误消息,您可以:

http://sqlfiddle.com/#!9/2697e/3

create or replace view example_view   as
select username 
from example
where substring_index(user(), '@', 1)  = example.username COLLATE latin1_general_cs;

http://sqlfiddle.com/#!9/bf88d/1


0
投票

我有类似的问题,但我改变了my.ini

ProgramData\MySQL\MySQL Server 5.7\my.ini

在文件中,在[mysqld]部分我放了这些行(我需要的):

character-set-server=utf8

collation-server=utf8_hungarian_ci
© www.soinside.com 2019 - 2024. All rights reserved.