Внимание: MySQL считает, что буквы «ё» и «е» — одно и то же.
Увы, MySQL, если выбрать кодировку Unicode, считает, что «е» и «ё» — это одно и то же. Багом это не считается, в официальной таблице, где описано как MySQL 6.0 сравнивает символы, эти символы в одном ряду.
mysql> set names utf8 collate utf8_unicode_ci;
Query OK, 0 rows affected (0.00 sec)
mysql> select 'е'='ё', 'ё'='ѐ'\G
*************************** 1. row ***************************
'е'='ё': 1
'ё'='ѐ': 1
1 row in set (0.00 sec)Самое печальное, это нелогичное поведение всплывает, если есть потребность перевести базу с CP1251
mysql> set names cp1251;
Query OK, 0 rows affected (0.00 sec)
mysql> select 'е'='ё', 'ё'='ѐ'\G
*************************** 1. row ***************************
'е'='ё': 0
'ё'='ѐ': 0
1 row in set (0.00 sec)Чем это может быть плохо? Например, у нас
mysql> set names utf8 collate utf8_unicode_ci;
Query OK, 0 rows affected (0.00 sec)
mysql> create table surname(surname varchar(255) primary key);
Query OK, 0 rows affected (0.07 sec)
mysql> insert into surname values('Рублёв');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into surname values('Рублев');
ERROR 1062 (23000): Duplicate entry 'Рублев' for key 'PRIMARY'Я придумал только один способ, исправляющий это поведение (но у него есть недостаток):
mysql> create table surname(surname varchar(255) primary key collate 'utf8_bin');
Query OK, 0 rows affected (0.02 sec)
mysql> insert into surname values('Рублёв');
Query OK, 1 row affected (0.00 sec)
mysql> insert into surname values('Рублев');
Query OK, 1 row affected (0.00 sec)
mysql> select * from surname where surname='рублев';
Empty set (0.00 sec)Я выключил case insensitive у данного столбца, явным указанием «collate». Это полностью решает проблему с «ё», но лишает нас удовольствия искать, не заботясь о совпадении регистра.
Комментарии 18
select * from surnames where LOWER(surname) = LOWER('Рублёв') ?
Комментарий для dinoel:
В каких условиях?
Да, я знаю, в TODO записан, но никак не пойдут руки поправить :( Но я поправлю.
create table surname(surname varchar(255) primary key collate 'utf8_bin');
вот в таких, т.е. при бинарном сравнении.
Хотя я догадываюсь :)
select * from surname where LOWER(surname)=LOWER('рублев');
| surname |
| Рублев |
1 row in set (0.00 sec)
mysql> select * from surname where LOWER(surname)=LOWER('рублёв');
| surname |
| Рублёв |
Комментарий для dinoel:
С сортировкой и использованием индекса.
А также сортировать, сравнивать и искать.
До сих пор из того факта, что MySQL по умолчанию сравнивает строки регистронезависимо или же приравнивает «ü» и «u», я выносил для себя только широкий спектр проблем, которые приходилось так или иначе решать.
А именно в /usr/share/mysql/charsets/Index.xml изменил
Unicode
primary
compiled
binary
compiled
\u0415
\u0401
\u0435
\u0451
и добавил:
Unicode
\u0415
\u0401
\u0435
\u0451
после чего выполнил:
ALTER TABLE `таблица` CHANGE `столбец` `столбец` тип CHARACTER SET utf8mb4 COLLATE utf8mb4_russian_ci NOT NULL DEFAULT '';