Как я могу сделать сравнение строк с учетом регистра SQL в MySQL? - PullRequest
251 голосов
/ 12 апреля 2011

У меня есть функция, которая возвращает пять символов в смешанном регистре. Если я сделаю запрос по этой строке, он вернет значение независимо от регистра.

Как сделать строковые запросы MySQL чувствительными к регистру?

Ответы [ 11 ]

652 голосов
/ 12 апреля 2011

Хорошей новостью является то, что если вам нужно сделать запрос с учетом регистра, это очень легко сделать:

SELECT *  FROM `table` WHERE BINARY `column` = 'value'
138 голосов
/ 12 апреля 2011

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

Если вы хотите, чтобы столбец всегда обрабатывался с учетом регистра, объявите его с учетом регистра или двоичным сопоставлением.

35 голосов
/ 26 сентября 2011

Вместо использования оператора = вы, возможно, захотите использовать 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'

Это займет «a», а не «A» в своем состоянии

34 голосов
/ 26 июля 2016

Ответ опубликован Крейгом Уайтом, имеет большое снижение производительности

SELECT *  FROM `table` WHERE BINARY `column` = 'value'

, потому что он не использует индексы.Таким образом, либо вам нужно изменить сопоставление таблицы, как упомянуто здесь https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html.

ИЛИ

Самое простое исправление, вы должны использовать двоичный файл значения.1012 * Например.

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 |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+

VS

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 с)

13 голосов
/ 04 декабря 2013

Чтобы использовать индекс перед использованием BINARY, вы можете сделать что-то подобное, если у вас большие таблицы.

SELECT
   *
FROM
   (SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
   BINARY `column` = 'value'

Подзапрос приведет к действительно небольшому подмножеству без учета регистра, которое вызатем выберите единственное совпадение с учетом регистра.

7 голосов
/ 03 января 2013

Ниже приведены для версий 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" как "чувствительный к регистру" - ???).

5 голосов
/ 29 июня 2016

Вы можете использовать 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 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+  
2 голосов
/ 24 мая 2019

Наиболее правильный способ сравнения строк с учетом регистра без изменения параметров сортировки запрашиваемого столбца - это явное указание набора символов и параметров сравнения для значения, с которым сравнивается столбец.

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 к значению, а не кcolumn?

Когда вы применяете любую функцию преобразования к столбцу перед сравнением, он не позволяет обработчику запросов использовать индекс, если он существует для столбца, что может значительно замедлить ваш запрос.Поэтому всегда лучше преобразовывать значение, где это возможно.Когда выполняется сравнение между двумя строковыми значениями, и одно из них имеет явно заданное сопоставление, механизм запросов будет использовать явное сопоставление независимо от того, к какому значению оно применяется.

Accent Sensitivity

Важно отметить, что MySql не только нечувствителен к регистру для столбцов, использующих параметры сортировки _ci (как правило, по умолчанию), но также нечувствителен к accent .Это означает, что 'é' = 'e'.Использование двоичного сопоставления (или оператора binary) сделает сравнение строк чувствительным к акценту, а также к регистру.

Что такое utf8mb4?

Набор символов utf8 в MySqlэто псевдоним для utf8mb3, который в последних версиях устарел , поскольку он не поддерживает 4-байтовые символы (что важно для кодирования строк, таких как ?).Если вы хотите использовать кодировку UTF8 с MySql, вам следует использовать кодировку utf8mb4.

1 голос
/ 17 февраля 2017

Нет необходимости что-либо менять на уровне БД, просто нужно внести изменения в SQL-запрос, он будет работать.

Пример -

"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";

Двоичное ключевое слово будетсделать регистр чувствительным.

1 голос
/ 25 апреля 2013

Отлично!

Я поделюсь с вами кодом из функции, которая сравнивает пароли:

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;
...