У меня есть функция, которая возвращает пять символов в смешанном регистре. Если я сделаю запрос по этой строке, он вернет значение независимо от регистра.
Как я могу сделать строковые запросы MySQL чувствительными к регистру?
У меня есть функция, которая возвращает пять символов в смешанном регистре. Если я сделаю запрос по этой строке, он вернет значение независимо от регистра.
Как я могу сделать строковые запросы MySQL чувствительными к регистру?
Ответы:
http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
Набор символов и параметры сортировки по умолчанию - latin1 и latin1_swedish_ci, поэтому при сравнении недвоичных строк по умолчанию регистр не учитывается. Это означает, что если вы ищете с col_name LIKE 'a%', вы получите все значения столбцов, которые начинаются с A или a. Чтобы сделать этот поиск чувствительным к регистру, убедитесь, что один из операндов имеет чувствительность к регистру или двоичное сопоставление. Например, если вы сравниваете столбец и строку, которые имеют набор символов latin1, вы можете использовать оператор COLLATE, чтобы у любого из операндов был параметр сравнения latin1_general_cs или latin1_bin:
col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin
Если вы хотите, чтобы столбец всегда обрабатывался с учетом регистра, объявите его с учетом регистра или двоичным сопоставлением.
SELECT 'email' COLLATE utf8_bin = 'Email'
Хорошей новостью является то, что если вам нужно сделать запрос с учетом регистра, это очень легко сделать:
SELECT * FROM `table` WHERE BINARY `column` = 'value'
convert(char(0x65,0xcc,0x88) using utf8)
(то есть e
с ¨
добавлением) и convert(char(0xc3,0xab) using utf8)
(то есть ë
), но добавление BINARY
сделает их неравными.
Ответ, опубликованный Крейгом Уайтом, имеет большой штраф
SELECT * FROM `table` WHERE BINARY `column` = 'value'
потому что он не использует индексы. Таким образом, либо вам нужно изменить порядок сортировки таблиц, как указано здесь https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html .
ИЛИ
Самое простое решение - использовать двоичный файл значения.
SELECT * FROM `table` WHERE `column` = BINARY 'value'
Например.
mysql> EXPLAIN SELECT * FROM temp1 WHERE BINARY col1 = "ABC" AND col2 = "DEF" ;
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | temp1 | ALL | NULL | NULL | NULL | NULL | 190543 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
В.С.
mysql> EXPLAIN SELECT * FROM temp1 WHERE col1 = BINARY "ABC" AND col2 = "DEF" ;
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
| 1 | SIMPLE | temp1 | range | col1_2e9e898e | col1_2e9e898e | 93 | NULL | 2 | Using index condition; Using where |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
enter code here
1 ряд в наборе (0,00 сек)
Вместо использования оператора = вы можете использовать LIKE или LIKE BINARY.
// this returns 1 (true)
select 'A' like 'a'
// this returns 0 (false)
select 'A' like binary 'a'
select * from user where username like binary 'a'
Это займет «а», а не «А» в своем состоянии
Чтобы использовать индекс перед использованием BINARY, вы можете сделать что-то подобное, если у вас большие таблицы.
SELECT
*
FROM
(SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
BINARY `column` = 'value'
Подзапрос приведет к действительно небольшому нечувствительному к регистру подмножеству, из которого вы затем выбираете единственное чувствительное к регистру совпадение.
Наиболее правильный способ сравнения строк с учетом регистра без изменения параметров сортировки запрашиваемого столбца - это явное указание набора символов и параметров сравнения для значения, с которым сравнивается столбец.
select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;
binary
?Использование binary
оператора нецелесообразно, поскольку он сравнивает фактические байты кодированных строк. Если вы сравните фактические байты двух строк, закодированных с использованием разных наборов символов, две строки, которые следует считать одинаковыми, могут быть не равны. Например, если у вас есть столбец, который использует latin1
набор символов, и ваш набор символов сервера / сеанса имеет значение utf8mb4
, то при сравнении столбца со строкой, содержащей акцент, такой как 'café', он не будет совпадать со строками, содержащими эту же строку! Это потому, что в latin1
é кодируется как байт, 0xE9
но в utf8
нем два байта:0xC3A9
.
convert
так же, какcollate
?Сопоставления должны соответствовать набору символов. Таким образом, если ваш сервер или сеанс настроен на использование latin1
набора символов, который вы должны использовать, collate latin1_bin
но если ваш набор символов - utf8mb4
вы должны использовать collate utf8mb4_bin
. Поэтому наиболее надежное решение - всегда преобразовывать значение в наиболее гибкий набор символов и использовать двоичное сопоставление для этого набора символов.
convert
и collate
к значению, а не к столбцу?Когда вы применяете любую функцию преобразования к столбцу перед выполнением сравнения, он не позволяет обработчику запросов использовать индекс, если он существует для столбца, что может значительно замедлить ваш запрос. Поэтому всегда лучше преобразовывать значение, где это возможно. Когда сравнение выполняется между двумя строковыми значениями, и одно из них имеет явно заданное сопоставление, механизм запросов будет использовать явное сопоставление независимо от того, к какому значению оно применяется.
Важно отметить, что MySql не только нечувствителен к регистру столбцов, использующих параметры _ci
сортировки (как правило, по умолчанию), но также нечувствителен к акценту . Это значит что 'é' = 'e'
. Использование двоичного сопоставления (или binary
оператора) сделает сравнение строк чувствительным к акценту, а также к регистру.
utf8mb4
?Набор utf8
символов в MySql - это псевдоним, для utf8mb3
которого не рекомендуется в последних версиях, поскольку он не поддерживает 4-байтовые символы (что важно для кодирования строк, таких как 🐈). Если вы хотите использовать кодировку UTF8 с MySql, вам следует использовать utf8mb4
кодировку.
Следующее для версий MySQL, равных или выше, чем 5.5.
Добавить в /etc/mysql/my.cnf
[mysqld]
...
character-set-server=utf8
collation-server=utf8_bin
...
Все другие сопоставления, которые я пробовал, казались нечувствительными к регистру, работал только "utf8_bin".
Не забудьте перезапустить mysql после этого:
sudo service mysql restart
Согласно http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html есть также «latin1_bin».
"Utf8_general_cs" не был принят при запуске mysql. (Я читаю "_cs" как "чувствительный к регистру" - ???).
Вы можете использовать BINARY с учетом регистра, как это
select * from tb_app where BINARY android_package='com.Mtime';
к сожалению, этот sql не может использовать индекс, вы будете страдать от снижения производительности запросов, зависящих от этого индекса
mysql> explain select * from tb_app where BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | tb_app | NULL | ALL | NULL | NULL | NULL | NULL | 1590351 | 100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
К счастью, у меня есть несколько хитростей, чтобы решить эту проблему
mysql> explain select * from tb_app where android_package='com.Mtime' and BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | tb_app | NULL | ref | idx_android_pkg | idx_android_pkg | 771 | const | 1 | 100.00 | Using index condition |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
Превосходно!
Я поделюсь с вами кодом из функции, которая сравнивает пароли:
SET pSignal =
(SELECT DECODE(r.usignal,'YOURSTRINGKEY') FROM rsw_uds r WHERE r.uname =
in_usdname AND r.uvige = 1);
SET pSuccess =(SELECT in_usdsignal LIKE BINARY pSignal);
IF pSuccess = 1 THEN
/*Your code if match*/
ELSE
/*Your code if don't match*/
END IF;
declare pSuccess BINARY;
в начале
Не нужно ничего менять на уровне БД, просто нужно внести изменения в SQL Query, это будет работать.
Пример -
"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";
Двоичное ключевое слово сделает регистр чувствительным.