У мене є функція, яка повертає п'ять символів зі змішаним регістром. Якщо я виконую запит на цій рядку, він поверне значення незалежно від випадку.
Як я можу зробити рядки запитів MySQL у регістрі?
У мене є функція, яка повертає п'ять символів зі змішаним регістром. Якщо я виконую запит на цій рядку, він поверне значення незалежно від випадку.
Як я можу зробити рядки запитів MySQL у регістрі?
Відповіді:
http://dev.mysql.com/doc/refman/5.0/uk/case-sensibility.html
Набір символів та зіставлення за замовчуванням - latin1 та latin1_swedish_ci, тому порівняння рядків небінарних рядків за замовчуванням нечутливе до регістру. Це означає, що якщо здійснити пошук з іменем col_ 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/uk/case-sensibility.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 |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
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 сек)
Замість використання оператора = Ви можете скористатися 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-sensibility.html також існує "latin1_bin".
Запуск mysql не було прийнято "utf8_general_cs". (Я читаю "_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 + "'";
Двійкове ключове слово зробить чутливі до регістру.