¿Cómo puedo hacer una comparación de cadenas de mayúsculas y minúsculas de SQL en MySQL?


285

Tengo una función que devuelve cinco caracteres con mayúsculas y minúsculas. Si hago una consulta en esta cadena, devolverá el valor independientemente del caso.

¿Cómo puedo hacer que las consultas de cadena MySQL distingan entre mayúsculas y minúsculas?



8
Tenga en cuenta que BINARY no es lo mismo que la comparación entre mayúsculas y minúsculas: seleccione 'à' como 'a' // devuelve verdadero seleccione 'à' like BINARY 'a' // devuelve falso !!! seleccione 'à' como 'a' COLLATE latin1_general_cs // devuelve true Entonces la sugerencia de usar BINARY para la comparación entre mayúsculas y minúsculas es incorrecta.
cquezel

3
@cquezel: Entonces, ¿estás diciendo que [seleccionar 'à' como BINARY 'a'] debería ser verdadero? En cualquier caso, ¿qué tiene esto que ver con las comparaciones entre mayúsculas y minúsculas?
Francisco Zarabozo

3
@FranciscoZarabozo, algunas personas a continuación sugirieron usar la comparación BINARIA para hacer una comparación entre mayúsculas y minúsculas. Solo estoy señalando que en otros idiomas, esto probablemente no funcionará como se esperaba, ya que BINARY no es lo mismo que mayúsculas y minúsculas.
cquezel

3
@cquezel Creo que 'à' es una letra diferente a 'a'. Entonces, la comparación entre los dos debería ser falsa en cualquier caso.
Stephane

Respuestas:


159

http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html

El conjunto de caracteres y la clasificación predeterminados son latin1 y latin1_swedish_ci, por lo que las comparaciones de cadenas no binarias no distinguen entre mayúsculas y minúsculas de forma predeterminada. Esto significa que si busca con col_name LIKE 'a%', obtendrá todos los valores de columna que comienzan con A o a. Para hacer que esta búsqueda distinga entre mayúsculas y minúsculas, asegúrese de que uno de los operandos tenga una intercalación binaria o entre mayúsculas y minúsculas. Por ejemplo, si está comparando una columna y una cadena que tienen el conjunto de caracteres latin1, puede usar el operador COLLATE para hacer que cualquiera de los operandos tenga la clasificación latin1_general_cs o 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 desea que una columna siempre se trate con mayúsculas y minúsculas, declarela con una intercalación binaria o con mayúsculas y minúsculas.


44
¿Alguna pista sobre cómo hacer esto en phpmyadmin?
StevenB

44
@StevenB: Haga clic en el botón Editar de la columna, a continuación, establecer la intercalación -> i.imgur.com/7SoEw.png
esclavo

32
@BT Para que la columna utf8 distinga entre mayúsculas y minúsculas, puede usar la combinación bin como:SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr

@drudge ¿Cómo declararía una columna con una clasificación entre mayúsculas y minúsculas?
Stephane

1
@StephaneEybert si está buscando mayúsculas y minúsculas, he tenido suerte al usar varbinary en lugar de varchar para un campo en la tabla ut8. HTH
Andrew T

724

La buena noticia es que si necesita hacer una consulta entre mayúsculas y minúsculas, es muy fácil de hacer:

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

34
Esto es exactamente lo que estaba buscando. Lo subiría más si pudiera. Sin embargo, una pregunta, ¿qué efecto tiene esto en el rendimiento? Lo estoy usando en un informe limitado, por lo que no es importante en mi caso, pero tengo curiosidad.
adjwilli

23
¿Por qué esta no es la respuesta? Esto es exactamente lo que necesitaba también.
Art Geigel

77
@adjwilli Si la columna era parte de un índice, sufrirá un impacto en el rendimiento de las consultas que dependen de ese índice. Para mantener el rendimiento, debe modificar la tabla.
dshin

66
¿Qué hará esto para las cadenas UTF-8 que contienen el mismo carácter con una representación diferente, por ejemplo, usando un carácter de combinación para agregar una diéresis? Estas cadenas UTF-8 podrían tratarse como iguales: convert(char(0x65,0xcc,0x88) using utf8)(es decir, econ ¨agregado) y convert(char(0xc3,0xab) using utf8)(es decir ë), pero sumar las BINARYhará desiguales.
mvds

3
Como ejemplo de rendimiento: mi consulta pasa de 3,5 ms (insignificante) a 1,570 ms (esto es aproximadamente un segundo y medio), consultando una tabla con 1.8M filas aproximadamente.
Lluís Suñol

64

Respuesta publicada por Craig White, tiene una gran penalización de rendimiento

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

porque no usa índices. Entonces, o bien debe cambiar la clasificación de la tabla como se menciona aquí https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html .

O

La solución más fácil, debe usar un BINARIO de valor.

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

P.ej.

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 fila en conjunto (0.00 seg)


Esto no parece ser sensible a mayúsculas y minúsculas en 10.3.22-MariaDB (usando libmysql - 5.6.43)
user10398534

40

En lugar de usar el operador =, es posible que desee usar LIKE o 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'

Tomará 'a' y no 'A' en su condición


Esto no parece ser sensible a mayúsculas y minúsculas en 10.3.22-MariaDB (usando libmysql - 5.6.43)
user10398534

17

Para hacer uso de un índice antes de usar el BINARIO, puede hacer algo como esto si tiene tablas grandes.

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

La subconsulta daría como resultado un subconjunto de mayúsculas y minúsculas realmente pequeño del cual luego se selecciona la única coincidencia entre mayúsculas y minúsculas.


Vale la pena comentar que lo anterior solo ayudará en función de sus datos: su búsqueda insensible a mayúsculas y minúsculas podría devolver un subconjunto de datos bastante grande.
BrynJ

15

La forma más correcta de realizar una comparación de cadenas entre mayúsculas y minúsculas sin cambiar la clasificación de la columna que se consulta es especificar explícitamente un conjunto de caracteres y clasificación para el valor con el que se compara la columna.

select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;

¿Por qué no usar binary?

El uso del binaryoperador no es aconsejable porque compara los bytes reales de las cadenas codificadas. Si compara los bytes reales de dos cadenas codificadas usando los diferentes juegos de caracteres, dos cadenas que deben considerarse iguales pueden no ser iguales. Por ejemplo, si tiene una columna que usa el latin1conjunto de caracteres, y su conjunto de caracteres de servidor / sesión lo es utf8mb4, cuando compara la columna con una cadena que contiene un acento como 'café', ¡no coincidirá con las filas que contienen esa misma cadena! Esto es debido a que en latin1é se encuentra codificado como el byte 0xE9pero en utf8ella es de dos bytes: 0xC3A9.

¿Por qué usar converttan bien como collate?

Las intercalaciones deben coincidir con el conjunto de caracteres. Entonces, si su servidor o sesión está configurado para usar el latin1juego de caracteres, debe usarlo, collate latin1_binpero si su juego de caracteres es utf8mb4, debe usarlo collate utf8mb4_bin. Por lo tanto, la solución más sólida es convertir siempre el valor en el conjunto de caracteres más flexible y utilizar la intercalación binaria para ese conjunto de caracteres.

¿Por qué aplicar el converty collateal valor y no la columna?

Cuando aplica cualquier función de transformación a una columna antes de hacer una comparación, evita que el motor de consulta use un índice si existe para la columna, lo que podría ralentizar drásticamente su consulta. Por lo tanto, siempre es mejor transformar el valor donde sea posible. Cuando se realiza una comparación entre dos valores de cadena y uno de ellos tiene una clasificación explícitamente especificada, el motor de consulta utilizará la clasificación explícita, independientemente del valor al que se aplique.

Sensibilidad acento

Es importante tener en cuenta que MySql no solo distingue entre mayúsculas y minúsculas para las columnas que usan una _ciintercalación (que generalmente es la predeterminada), sino que también es insensible al acento . Esto significa que 'é' = 'e'. El uso de una intercalación binaria (o el binaryoperador) hará que las comparaciones de cadenas sean sensibles al acento y a mayúsculas y minúsculas.

¿Qué es utf8mb4?

El utf8conjunto de caracteres en MySql es un alias para el utf8mb3cual ha sido desaprobado en las versiones recientes porque no admite caracteres de 4 bytes (lo cual es importante para codificar cadenas como 🐈). Si desea usar la codificación de caracteres UTF8 con MySql, entonces debería estar usando el utf8mb4juego de caracteres.


8

Lo siguiente es para versiones de MySQL iguales o superiores a 5.5.

Añadir a /etc/mysql/my.cnf

  [mysqld]
  ...
  character-set-server=utf8
  collation-server=utf8_bin
  ...

Todas las demás colaciones que probé parecían ser sensibles a mayúsculas y minúsculas, solo "utf8_bin" funcionó.

No olvide reiniciar mysql después de esto:

   sudo service mysql restart

De acuerdo con http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html también hay un "latin1_bin".

El inicio de mysql no aceptó "utf8_general_cs". (Leí "_cs" como "mayúsculas y minúsculas" - ???).


7

Puede usar BINARY para mayúsculas y minúsculas como este

select * from tb_app where BINARY android_package='com.Mtime';

desafortunadamente este sql no puede usar el índice, sufrirá un impacto en el rendimiento de las consultas que dependen de ese índice

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

Afortunadamente, tengo algunos trucos para resolver este problema.

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

Esto no parece ser sensible a mayúsculas y minúsculas en 10.3.22-MariaDB (usando libmysql - 5.6.43)
user10398534

2

¡Excelente!

Comparto con ustedes el código de una función que compara las contraseñas:

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;

Necesito agregar declare pSuccess BINARY;al inicio
adinas

2

No es necesario cambiar nada en el nivel de base de datos, solo tiene que cambiar en la consulta SQL, funcionará.

Ejemplo

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

La palabra clave binaria distingue entre mayúsculas y minúsculas.


1

mysql no distingue entre mayúsculas y minúsculas por defecto, intente cambiar la intercalación de idiomas a latin1_general_cs

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.