Внимание: 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 на UTF-8, так как в 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 так не считает (для простоты опускаю другие поля):

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

dinoel № 2
Кстати, заметил баг — если имя не вводить, то выдаст ошибку «введите имя или адрес блога» , но текст комментария пропадёт. Неприятно.
Евгений Степанищев (bolknote.ru) автор № 3

Комментарий для dinoel:

Интересно. А что вернёт
select * from surnames where LOWER(surname) = LOWER('Рублёв')?

В каких условиях?

Кстати, заметил баг — если имя не вводить, то выдаст ошибку «введите имя или адрес блога» , но текст комментария пропадёт. Неприятно.

Да, я знаю, в TODO записан, но никак не пойдут руки поправить :( Но я поправлю.

dinoel № 4
В каких условиях?

create table surname(surname varchar(255) primary key collate 'utf8_bin');
вот в таких, т.е. при бинарном сравнении.
Хотя я догадываюсь :)

dinoel № 5
Проверил, работает как надо. Т.е. проблема с регистром решается просто

select * from surname where LOWER(surname)=LOWER('рублев');
+--------------+
| surname |
+--------------+
| Рублев |
+--------------+
1 row in set (0.00 sec)

mysql> select * from surname where LOWER(surname)=LOWER('рублёв');
+--------------+
| surname |
+--------------+
| Рублёв |
+--------------+
Евгений Степанищев (bolknote.ru) автор № 7

Комментарий для dinoel:

Другое дело что с сортировкой будут проблемы..

С сортировкой и использованием индекса.

besisland (besisland.name) № 8
Я считаю, что подобное обращение с пользовательскими данными со стороны СУБД есть мерзость и грех великий. Кто ей разрешал брать на себя такую ответственность? Её дело — данные хранить.
Евгений Степанищев (bolknote.ru) автор № 10
Путать «е» и «ё» — точно великий грех. Это неудобно. В конце концов, кроме помощника кроссвордиста существует ещё множество других задач, которые хочется писать с использованием этой БД.
maxim-zotov (maxim-zotov.livejournal.com) № 11
mysql поступает очень правильно. У «ё» давно нет прав, и не mysql их у неё отобрал, потакать желаниям считанных пуристов — это усложнять жизнь миллионам обычных людей, которые ищут и заносят в базы данных «Рублев» и «Ежик в тумане».
besisland (besisland.name) № 13
Комментарий для dinoel:

До сих пор из того факта, что MySQL по умолчанию сравнивает строки регистронезависимо или же приравнивает «ü» и «u», я выносил для себя только широкий спектр проблем, которые приходилось так или иначе решать.
Дмитрий (http://www.kains.ru) № 16
Хм… Полезное однако иследование… Хотя, если честно, то ё редко где можно увидеть, все давно уже используют е заместо ё… Но опять таки с точки зрения русского языка правильнее будет именно ё…
Евгений Степанищев (bolknote.ru) автор № 17
Например, в фамилиях и географических названиях нельзя без «ё».
NightFox № 18
Решил проблему по примеру описаному здесь: http://www.sql.ru/forum/766045-2/besit-zhe … 3#11663963
А именно в /usr/share/mysql/charsets/Index.xml изменил

Unicode
UTF-8 Unicode
utf-8

primary
compiled

binary
compiled

\u0415

\u0401

\u0435

\u0451

и добавил:

Unicode
UTF-8 Unicode
utf-8

\u0415

\u0401

\u0435

\u0451

после чего выполнил:
ALTER TABLE `таблица` CHANGE `столбец` `столбец` тип CHARACTER SET utf8mb4 COLLATE utf8mb4_russian_ci NOT NULL DEFAULT '';