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) ...
,您应该得到 D197
或 C3AF
以获得正确存储的 YI
或 i-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 排序
我已经把我的小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) ...
,您应该得到 D197
或 C3AF
以获得正确存储的 YI
或 i-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 排序