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

190

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

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

  • 1
    Пожалуйста, оставьте свой запрос.
  • 1
    dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html
Показать ещё 6 комментариев
Теги:
case-sensitive
interop
string-comparison

11 ответов

110
Лучший ответ

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

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

  • 4
    Любой намек на то, как это сделать в phpmyadmin?
  • 4
    @StevenB: нажмите кнопку редактирования столбца, затем установите параметры сортировки -> i.imgur.com/7SoEw.png
Показать ещё 5 комментариев
499

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

SELECT *  FROM `table` WHERE BINARY `column` = 'value'
  • 29
    Это именно то, что я искал. Я бы поднялся выше, если бы мог. Вопрос, однако, как это влияет на производительность? Я использую это в ограниченных отчетах, так что в моем случае это не важно, но мне любопытно.
  • 22
    Почему это не ответ? Это именно то, что мне тоже нужно.
Показать ещё 13 комментариев
31

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

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

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

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

  • 0
    Стоит отметить, что вышеизложенное поможет только в зависимости от ваших данных - ваш поиск без учета регистра может потенциально вернуть довольно большое подмножество данных.
11

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

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

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

ИЛИ

Самое простое исправление, вы должны использовать BINARY значения.

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

Eg.

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

6

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

3

Вы можете использовать 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

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

Пример -

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

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

0

Как правило, так выглядит ваш запрос LIKE (вы видите, что я там сделал;-)):

SELECT * FROM WHERE LIKE '%%'

Теперь, чтобы сделать регистр без учета регистра, вы можете использовать функцию LOWER():

SELECT * FROM WHERE LOWER() LIKE LOWER ('%%');

Это поможет вам избежать попадания ваших рук в формат COLLATE и т.д. Вы знаете, что я говорю?

0

Отлично!

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

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;
  • 0
    Нужно добавить declare pSuccess BINARY; в начале
0

mysql по умолчанию не чувствителен к регистру, попробуйте изменить настройку языка на latin1_general_cs

Ещё вопросы

Сообщество Overcoder
Наверх
Меню