J'ai une fonction qui renvoie cinq caractères avec une casse mixte. Si je fais une requête sur cette chaîne, elle retournera la valeur indépendamment de la casse.
Comment puis-je rendre les requêtes de chaînes MySQL sensibles à la casse?
J'ai une fonction qui renvoie cinq caractères avec une casse mixte. Si je fais une requête sur cette chaîne, elle retournera la valeur indépendamment de la casse.
Comment puis-je rendre les requêtes de chaînes MySQL sensibles à la casse?
Réponses:
http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
Le jeu de caractères et le classement par défaut sont latin1 et latin1_swedish_ci, donc les comparaisons de chaînes non binaires ne respectent pas la casse par défaut. Cela signifie que si vous recherchez avec col_name LIKE 'a%', vous obtenez toutes les valeurs de colonne qui commencent par A ou a. Pour rendre cette recherche sensible à la casse, assurez-vous que l'un des opérandes a un classement sensible à la casse ou binaire. Par exemple, si vous comparez une colonne et une chaîne qui ont toutes deux le jeu de caractères latin1, vous pouvez utiliser l'opérateur COLLATE pour que l'un ou l'autre opérande ait le classement latin1_general_cs ou 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
Si vous souhaitez qu'une colonne soit toujours traitée de manière sensible à la casse, déclarez-la avec un classement sensible à la casse ou binaire.
SELECT 'email' COLLATE utf8_bin = 'Email'
La bonne nouvelle est que si vous avez besoin de faire une requête sensible à la casse, c'est très simple:
SELECT * FROM `table` WHERE BINARY `column` = 'value'
convert(char(0x65,0xcc,0x88) using utf8)
(c'est- e
à- dire avec ¨
ajouté) et convert(char(0xc3,0xab) using utf8)
(c'est-à-dire ë
), mais l'ajout BINARY
les rendra inégales.
Réponse publiée par Craig White, a une grosse pénalité de performance
SELECT * FROM `table` WHERE BINARY `column` = 'value'
car il n'utilise pas d'index. Donc, soit vous devez modifier le classement du tableau comme mentionné ici https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html .
OU
Solution la plus simple, vous devez utiliser un BINAIRE de valeur.
SELECT * FROM `table` WHERE `column` = BINARY 'value'
Par exemple.
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 |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
CONTRE
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 rangée en jeu (0,00 sec)
Au lieu d'utiliser l'opérateur =, vous pouvez utiliser LIKE ou 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'
Il prendra "A" et non "A" dans son état
Pour utiliser un index avant d'utiliser BINARY, vous pouvez faire quelque chose comme ceci si vous avez de grandes tables.
SELECT
*
FROM
(SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
BINARY `column` = 'value'
La sous-requête entraînerait un très petit sous-ensemble insensible à la casse dont vous sélectionnez ensuite la seule correspondance sensible à la casse.
La façon la plus correcte d'effectuer une comparaison de chaînes sensible à la casse sans modifier le classement de la colonne interrogée consiste à spécifier explicitement un jeu de caractères et un classement pour la valeur à laquelle la colonne est comparée.
select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;
binary
?L'utilisation de l' binary
opérateur est déconseillée car elle compare les octets réels des chaînes codées. Si vous comparez les octets réels de deux chaînes codées en utilisant les différents jeux de caractères deux chaînes qui doivent être considérées comme identiques, elles peuvent ne pas être égales. Par exemple, si vous avez une colonne qui utilise le latin1
jeu de caractères et que votre jeu de caractères de serveur / session l'est utf8mb4
, alors lorsque vous comparez la colonne avec une chaîne contenant un accent tel que «café», elle ne correspondra pas aux lignes contenant la même chaîne! En effet , dans latin1
é est codé comme l'octet 0xE9
mais utf8
il est deux octets: 0xC3A9
.
convert
aussi bien collate
?Les classements doivent correspondre au jeu de caractères. Donc, si votre serveur ou session est configuré pour utiliser le latin1
jeu de caractères, vous devez utiliser, collate latin1_bin
mais si votre jeu de caractères est que utf8mb4
vous devez utiliser collate utf8mb4_bin
. Par conséquent, la solution la plus robuste consiste à toujours convertir la valeur dans le jeu de caractères le plus flexible et à utiliser le classement binaire pour ce jeu de caractères.
convert
et collate
à la valeur et non à la colonne?Lorsque vous appliquez une fonction de transformation à une colonne avant d'effectuer une comparaison, cela empêche le moteur de requête d'utiliser un index s'il en existe un pour la colonne, ce qui pourrait considérablement ralentir votre requête. Par conséquent, il est toujours préférable de transformer la valeur à la place lorsque cela est possible. Lorsqu'une comparaison est effectuée entre deux valeurs de chaîne et que l'une d'entre elles a un classement explicitement spécifié, le moteur de requête utilise le classement explicite, quelle que soit la valeur à laquelle il est appliqué.
Il est important de noter que MySql est non seulement sensible à la casse pour les colonnes en utilisant un _ci
assemblage (qui est généralement la valeur par défaut), mais aussi l' accent insensible. Cela veut dire que 'é' = 'e'
. L'utilisation d'un classement binaire (ou de l' binary
opérateur) rendra les comparaisons de chaînes sensibles à l'accent ainsi qu'à la casse.
utf8mb4
?Le utf8
jeu de caractères dans MySql est un alias utf8mb3
qui a été déprécié dans les versions récentes car il ne prend pas en charge les caractères à 4 octets (ce qui est important pour coder des chaînes comme 🐈). Si vous souhaitez utiliser le codage de caractères UTF8 avec MySql, vous devez utiliser le utf8mb4
jeu de caractères.
Ce qui suit est pour les versions de MySQL égales ou supérieures à 5.5.
Ajouter à /etc/mysql/my.cnf
[mysqld]
...
character-set-server=utf8
collation-server=utf8_bin
...
Toutes les autres collations que j'ai essayées ne semblaient pas sensibles à la casse, seul "utf8_bin" fonctionnait.
N'oubliez pas de redémarrer mysql après ceci:
sudo service mysql restart
Selon http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html, il existe également un "latin1_bin".
Le "utf8_general_cs" n'a pas été accepté par le démarrage de mysql. (J'ai lu "_cs" comme "sensible à la casse" - ???).
Vous pouvez utiliser BINARY pour respecter la casse comme celui-ci
select * from tb_app where BINARY android_package='com.Mtime';
malheureusement, ce sql ne peut pas utiliser l'index, vous subirez un impact sur les performances des requêtes dépendantes de cet index
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 |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
Heureusement, j'ai quelques astuces pour résoudre ce problème
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 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
Excellent!
Je partage avec vous le code d'une fonction qui compare les mots de passe:
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;
au début
Pas besoin de changer quoi que ce soit au niveau de la base de données, il vous suffit de modifier les requêtes SQL, cela fonctionnera.
Exemple -
"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";
Le mot-clé binaire rendra la casse sensible.