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

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

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


person StevenB    schedule 12.04.2011    source источник
comment
dev.mysql.com/doc/refman/5.0/ ru / charset-binary-op.html   -  person AgentConundrum    schedule 12.04.2011
comment
Обратите внимание, что BINARY - это не то же самое, что сравнение с учетом регистра: select 'à' как 'a' // возвращает true select 'à' как BINARY 'a' // возвращает false !!! выберите 'à' like 'a' COLLATE latin1_general_cs // возвращает true Таким образом, предложение использовать BINARY для сравнения с учетом регистра неверно.   -  person cquezel    schedule 02.12.2011
comment
@cquezel: Итак, вы говорите, что [select 'à', как BINARY 'a'] должен возвращать истину ?? В любом случае, какое это имеет отношение к сравнениям с учетом регистра?   -  person Francisco Zarabozo    schedule 31.03.2013
comment
@FranciscoZarabozo некоторые люди ниже предложили использовать сравнение BINARY для сравнения с учетом регистра. Я просто указываю, что на других языках это, вероятно, не будет работать должным образом, поскольку BINARY - это не то же самое, что и регистр.   -  person cquezel    schedule 10.05.2014
comment
@cquezel Я бы подумал, что «à» - это другая буква, чем «а». Таким образом, сравнение между ними действительно должно быть ложным в любом случае.   -  person Stephane    schedule 11.10.2014
comment
@StephaneEybert в любом случае? Но почему существуют сопоставления без учета акцента? снова: выберите «à», как «a» COLLATE latin1_general_cs вернет true. Вот пример: Моя кредитная карта VISA не принимает акценты от моего имени, но мой банк принимает!   -  person cquezel    schedule 14.10.2014
comment
Я выбрал глобальную конфигурацию и сделал все таблицы чувствительными к регистру: ENGINE = InnoDB DEFAULT CHARSET = utf8 COLLATE utf8_bin;   -  person Stephane    schedule 14.10.2014
comment
Примечание: это можно воспроизвести без использования каких-либо таблиц: SELECT 'a' = 'A'; # Result: 1. Это может зависеть от каких-то глобальных настроек.   -  person donquixote    schedule 13.07.2019


Ответы (11)


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

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

person drudge    schedule 12.04.2011
comment
любой намек на то, как это сделать в phpmyadmin? - person StevenB; 12.04.2011
comment
@StevenB: нажмите кнопку столбца «Изменить», затем установите параметры сортировки - ›i.imgur.com/7SoEw. png - person drudge; 12.04.2011
comment
@BT Чтобы сделать столбец utf8 чувствительным к регистру, вы можете использовать сортировку bin, например: SELECT 'email' COLLATE utf8_bin = 'Email' - person piotrekkr; 23.04.2013
comment
@drudge Как бы вы объявили столбец с сортировкой с учетом регистра? - person Stephane; 11.10.2014
comment
Вот пример, который мне подходит: ВЫБЕРИТЕ имя ИЗ ASA ГДЕ CAST (имя КАК ДВОИЧНОЕ) КАК "% Net%" - person JScarry; 05.12.2014
comment
@StephaneEybert, если вы ищете прямую чувствительность к регистру, мне посчастливилось использовать varbinary вместо varchar для поля в таблице ut8. HTH - person Andrew T; 05.01.2015
comment
Я меняю столбец Collation на latin1_bin, но он не работает, почему? Только сопоставление в запросе работает. - person jw_; 16.09.2019
comment
@jw_ (я) Причина в том, что MySQL Workbench 6.3, похоже, содержит ошибку, когда вы устанавливаете двоичный столбец или устанавливаете сопоставление столбцов на latin1_bin и Apply, ничего не меняется. Решение состоит в том, чтобы переименовать столбец и одновременно изменить настройку, а затем снова переименовать ее. - person jw_; 24.09.2019
comment
В MYSQL очень мало сопоставлений, не чувствительных к двоичному регистру. Относительно новый набор символов utf8mb4 кажется полным. Все те, которые вы ищете, оканчиваются на _cs. Есть представление в кодировке latin7. Я был удивлен тем, что пришел из среды SQLServer, у меня была такая же сортировка в _ci, а также в _cs - person theking2; 30.04.2020

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

SELECT *  FROM `table` WHERE BINARY `column` = 'value'
person Craig White    schedule 12.04.2011
comment
Это именно то, что я искал. Я бы поднялся выше, если бы мог. Однако возникает вопрос, как это влияет на производительность? Я использую его для ограниченной отчетности, поэтому в моем случае это не важно, но мне любопытно. - person adjwilli; 25.08.2012
comment
Почему это не ответ? Это именно то, что мне было нужно. - person Art Geigel; 26.07.2013
comment
@adjwilli Если столбец был частью индекса, производительность запросов, зависящих от этого индекса, снизится. Чтобы поддерживать производительность, вам нужно фактически изменить таблицу. - person dshin; 19.09.2013
comment
@David Моя таблица должна быть в UTF8, и это было частью сценария экспорта, поэтому я думаю, что компромисс в производительности того стоит. Но полезно знать, чтобы не использовать это в часто выполняемых запросах. - person adjwilli; 19.09.2013
comment
Мне было бы интересно увидеть разницу в производительности между этим методом и методом latin1_bin, описанным выше. Возможно, мне придется провести несколько тестов, когда у меня появится шанс, и я опубликую свои результаты. - person TMH; 20.05.2014
comment
Что это будет делать для строк UTF-8, содержащих один и тот же символ с другим представлением, например используя комбинированный символ для добавления умляута? Эти строки UTF-8 можно рассматривать как равные: convert(char(0x65,0xcc,0x88) using utf8) (т.е. e с добавлением ¨) и convert(char(0xc3,0xab) using utf8) (т.е. ë), но добавление BINARY сделает их неравными. - person mvds; 08.06.2015
comment
Кроме того, сравнение типов с плавающей запятой дает странные результаты, когда при ДВОИЧНОМ сравнении значения не равны, хотя невооруженным глазом они кажутся равными. - person mvds; 08.06.2015
comment
Проверено, это не работает для символов, отличных от ASCII, но работает с решением COLLATE latin1_bin. - person Jean Vincent; 26.08.2015
comment
@JeanVincent, можешь опубликовать пример? Для меня это работает SELECT BINARY 'Ñ'='Ñ', BINARY 'Ñ'='ñ' (возвращает 1 и 0) - person golimar; 02.06.2016
comment
Не могли бы вы показать, как это должно выглядеть в операторе вставки? - person Putnik; 13.01.2017
comment
Может ли ОП наконец прийти сюда и принять этот ответ? Мы не приходим на SO, чтобы найти копии / вставки непонятной документации. - person Sylvain B; 16.03.2017
comment
как заявил Жан Винсент, это не работает с символами, отличными от ASCII, если у вас есть запись, такая как à vendre, она не найдет ее при поиске BINAY col = à vendre - person Robert Sinclair; 04.12.2017
comment
Это также не работает при выполнении REPLACE INTO на основе уникальных индексов или аналогичных операций. (Как упоминалось выше, он также убьет сервер, если у вас много записей.) Этот ответ уместен в некоторых обстоятельствах, но не во всех. - person Robbie; 21.04.2018
comment
В качестве примера производительности: мой запрос проходит от 3,5 мс (незначительно) до 1,570 мс (это примерно полторы секунды), запрашивая таблицу с примерно 1,8 млн строк. - person Lluís Suñol; 25.02.2019
comment
Я рекомендую ответ @Nitesh из-за преимущества в производительности (используйте ключевое слово BINARY перед значением, а не перед столбцом, чтобы включить индексы) ... SELECT * FROM `table` WHERE `column` = BINARY 'value' - person mikep; 18.12.2019
comment
Кажется, это не чувствительно к регистру в 10.3.22-MariaDB (с использованием libmysql - 5.6.43) - person user10398534; 21.04.2020
comment
Кажется, что это чувствительно к регистру на 10.3.23-MariaDB, хотя - person FaNo_FN; 21.09.2020

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

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

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

OR

Самое простое исправление, вы должны использовать ДВОИЧНОЕ значение.

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

E.g.

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

person Nitesh    schedule 25.07.2016
comment
Кажется, это не чувствительно к регистру в 10.3.22-MariaDB (с использованием libmysql - 5.6.43) - person user10398534; 21.04.2020
comment
Я использовал решение Крейга Уайта в течение года, но после нескольких жалоб на загрузку страницы я более внимательно посмотрел, внес изменения, рекомендованные Нитешем, и запрос изменился с 2,5 до 0,15 секунды. Индекс не использовался, когда Binary был до Where. После перемещения двоичного файла после того, как использовался индекс. Спасибо! - person michaelf; 20.09.2020
comment
Отличная идея, Нитеш! Это должен быть ответ, получивший наибольшее количество голосов - person billynoah; 18.11.2020

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

В его состоянии будет буква "А", а не "А".

person insoftservice    schedule 26.09.2011
comment
Кажется, это не чувствительно к регистру в 10.3.22-MariaDB (с использованием libmysql - 5.6.43) - person user10398534; 21.04.2020

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

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 .

person Paul Wheeler    schedule 23.05.2019

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

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

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

person Eric    schedule 04.12.2013
comment
Стоит отметить, что приведенное выше может помочь только в зависимости от ваших данных - ваш поиск без учета регистра потенциально может вернуть довольно большое подмножество данных. - person BrynJ; 10.08.2017

Вы можете использовать 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 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+  
person xiezefan    schedule 29.06.2016
comment
Кажется, это не чувствительно к регистру в 10.3.22-MariaDB (с использованием libmysql - 5.6.43) - person user10398534; 21.04.2020

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

person fritzthecat    schedule 03.01.2013

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

Пример -

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

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

person Pappu Mehta    schedule 17.02.2017

Отлично!

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

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;
person Victor Enrique    schedule 25.04.2013
comment
Необходимо добавить declare pSuccess BINARY; в начале - person adinas; 05.08.2018

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

person ohmusama    schedule 12.04.2011