¿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?

StevenB
fuente
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.

esclava
fuente
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'
Craig White
fuente
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)

Nitesh
fuente
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

servicio insofts
fuente
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.

Eric
fuente
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.

Paul Wheeler
fuente
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" - ???).

fritzthecat
fuente
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 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+  
xiezefan
fuente
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;
Victor enrique
fuente
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.

Pappu Mehta
fuente
1

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

ohmusama
fuente