Categories
MySQL

Tip: Comparación de cadenas “case sensitive” en MySQL

Tip para hacer que las comparaciones de texto en MySQL sean case sensitive (distingan entre mayúsculas y minúsculas)

Antes que nada, un poco de teoría sobre conjuntos de caracteres (charset) y colaciones (collations):

Un conjunto de caracteres es un
conjunto de símbolos y codificaciones. Una
colación es un conjunto de
reglas para comparar caracteres en un conjunto de caracteres.
Vamos a dejar clara la distinción con un ejemplo de un conjunto
de caracteres imaginario.

Supongamos que tenemos un alfabeto con cuatro letras:
'A', 'B',
'a', 'b'. Damos a cada letra
un número: 'A' = 0, 'B' =
1, 'a' = 2, 'b' = 3. La
letra 'A' es un símbolo, el número 0 es la
codificación para
'A', y la combinación de las cuatro letras y
sus codificaciones es un conjunto de
caracteres
.

Suponga que queremos comparar dos cadenas de caracteres,
'A' y 'B'. La forma más
fácil de hacerlo es mirar las codificaciones: 0 para
'A' y 1 para 'B'. Ya que 0
es menor a 1, decimos que 'A' es menor que
'B'. Lo que acabamos de hacer es aplicar una
colación a un conjunto de caracteres. La colación es un conjunto
de reglas (sólo una en este caso): “compara las
codificaciones
”. LLamamos a la más sencilla de todas las
colaciones una colación binaria.

Pero, ¿qué pasa si queremos decir que las letras en mayúsculas
y minúsculas son equivalentes? Entonces tendríamos como mínimo
dos reglas: (1) tratar las letras minúsuclas
'a' y 'b' como equivalentes
a 'A' y 'B'; (2) luego
comparar las codificaciones. Llamamos a esto una colación
no sensible a mayúsuculas y minúsculas
(case-insensitive)
. Es un poco más compleja que una
colación binaria.

La forma más sencilla de que las comparaciones que se hacen sobre determinados campos distingan entre mayúsculas y minúsculas, es definir una colación binaria para éstas.

sql:

CREATE TABLE users (
        nick varchar(20) COLLATE utf8_bin,
        name varchar(200)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish_ci
code:

mysql> insert into users values('alex', 'Alex');
Query OK, 1 row affected (0.00 sec)

mysql> select nick from users where nick='alex';
+------+
| nick |
+------+
| alex |
+------+
1 row in set (0.00 sec)

mysql> select nick from users where nick='aleX';
Empty set (0.00 sec)

Pero existe un pequeño detalle con esa alternativa, porque por un motivo que desconozco, los espacios que existen en la parte de la derecha no son tomados en cuenta, es decir:

code:

mysql> select nick from users where nick = 'alex   ';
+------+
| nick |
+------+
| alex |
+------+
1 row in set (0.00 sec)

Para evitar este comportamiento en columnas que tengan o no colación binaria, se puede hacer uso del operador BINARY.

sql:

SELECT nick FROM users WHERE BINARY nick = 'alex   ';

/*
De acuerdo a los comentarios de http://dev.mysql.com/doc/refman/5.0/en/charset-binary-op.html,
la siguiente consulta es mejor para los índices sean usados.
*/

SELECT nick FROM users WHERE nick = BINARY 'alex   ';

code:

mysql> select nick from users where binary nick = 'alex   ';
Empty set (0.00 sec)

Debido a mi falta de conocimiento e interés en MySQL, es posible que en esta entrada -- inspirada en un bug de una aplicación que estoy desarrollando -- haya cometido más errores de los que normalmente cometo :). Tienen los comentarios abiertos por si quieren insultarme corregirme o aportar más información. 😉

One reply on “Tip: Comparación de cadenas “case sensitive” en MySQL”

Comments are closed.