MySQL: MySQL 表中的两个不同值被视为相同(不能设置唯一键)

MySQL: two different values in MySQL tables are treated as the same (can't set unique key)

我已经把我的小MySQLtable(手动缩小以定位问题)倾倒在这里:

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;



CREATE TABLE `symb` (
  `smb` varchar(200) NOT NULL,
  `trtmnt` varchar(200) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `symb` (`smb`, `trtmnt`) VALUES
('і', 'ty'),
('ї', 'hr');


/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

如果您创建上面的 MySQL table 和 运行 这个查询

select * from symb where smb = 'ї';

或这个(查询不同 - 请查看符号“ї”与“і”

select * from symb where smb = 'і';

然后你可能会看到你得到两行 selected 而不是我期望的一行。

再次强调,上面的这两个 select 查询是不同的 - 符号“ї”不同于“і”(两者都是西里尔符号,“і”在这里不是拉丁语)。

Collation chosen was utf8_general_ci

'і' 和 'ї' 被视为相同符号的任何原因以及使其不同的正确方法是什么?我需要 select 确切的行,而不是两行。

上面的查询在 phpMyAdmin 和 HeidiSQL 中进行了测试,这意味着 MySQL(整理?)问题,而不是用于 运行 查询的程序。 每个不同的符号都应视为不同的符号,table 应区分大小写。上面的 table 有什么问题?结果我无法为此行设置唯一键。

谢谢。

刚刚根据评论添加: SHOW TABLE STATUS LIKE 'symb' 显示什么? 它告诉我:

Name    symb
Engine  InnoDB
Version 10
Row_format  Compact
Rows    2
Avg_row_length  8192
Data_length 16384
Max_data_length 0
Index_length    0
Data_free   0
Auto_increment  NULL
Create_time 22.05.16 12:11
Update_time NULL
Check_time  NULL
Collation   utf8_general_ci
Checksum    NULL
Create_options  
Comment 

这就是您选择的排序规则的工作方式。您可以在这里查看更多信息:

因为您的 SELECT 语句返回了两条记录,您的数据似乎已被错误地编码为 UTF-8。因此,仅将 smb 列的编码从 Latin1 更改为 UTF-8 是行不通的。您的一种选择是将数据库转储为二进制文件,然后将其重新导入为 UTF-8:

mysqldump --add-drop-table your_database | replace CHARSET=latin1 CHARSET=utf8 |
    iconv -f latin1 -t utf8 | mysql your_database

阅读 here and here 了解更多信息。

你想要哪个?

D197       1111=x0457  [ї]    L  CYRILLIC SMALL LETTER YI
C3AF        239=x00EF  [ï]    L  LATIN SMALL LETTER I WITH DIAERESIS

如果您这样做 SELECT col, HEX(col) ...,您应该得到 D197C3AF 以获得正确存储的 YIi-umlaut。这是判断它是否正确存储为 utf8(或 utf8mb4)的最佳方式。

他们长得一样,待遇却不一样。所有 utf8/utf8mb4 归类将所有西里尔字母排在所有拉丁字母之后。

"best" "general" 排序规则是 utf8mb4_unicode_520_ci。 (utf8,不是utf8mb4,如果你不需要中文或者Emoji也可以。)

Here 是我对西欧字符在各种 utf8/utf8mb4 排序规则中的比较情况的总结。例如,utf8_spanish2_ci 是唯一将 ll 视为 'separate character' 的值,排在所有其他 l 值之后。 utf8_latvian_ci 将 ĶĻ 作为单独的字母处理。等等

SHOW TABLE STATUS 显示 默认 为 table;您需要查看 SHOW CREATE TABLE 以查看是否有任何列覆盖了该默认值。

我已经通过以下方式解决*这个问题:

1) 将 table 排序规则更改为 utf8mb4_unicode_520_ci

ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci

这允许您插入乌克兰字母表中除 ¥ 之外的所有字母。 这还允许您按照预期的方式对字母进行排序。

2) 将列排序规则更改为 utf8mb4_bin

ALTER TABLE table_name MODIFY column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

这允许您插入 ¡ 字符。

*这种方法的唯一缺点是排序时必须使用

SELECT * FROM table_name ORDER BY column_name COLLATE utf8mb4_unicode_520_ci ASC

但是,它仍然不会按 DESC 排序