在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()
之外,我该如何解决?
答案 0 :(得分:3)
问:为什么MySQL转换为latin1_swedish_ci
而不是latin1_general_cs
?
每个characterset都有一个默认排序规则。您可以使用 SHOW COLLATION
语句来查看此内容。输出中的摘录显示latin1_swedish_ci
是latin1
characterset的默认排序规则:
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 ...)
。您可以使用COLLATE
与CONVERT()
函数结合使用。
CONVERT(USER() USING latin1) COLLATE latin1_general_cs
注意:我对存储的视图没有任何实际经验;我们在整个地方使用内联视图。但我们从不创建存储的视图,因为存储的视图会导致无数的问题,更大的和更多问题,而不是视图定义的任何问题。解决方案。
答案 1 :(得分: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;
答案 2 :(得分:0)
我遇到了类似的问题,但是我更改了my.ini
:
ProgramData\MySQL\MySQL Server 5.7\my.ini
在文件的[mysqld]
下,放置了以下行(我需要):
character-set-server=utf8
collation-server=utf8_hungarian_ci