¿Cómo comparamos palabras que pueden contener acentos?
Un problema frecuente cuando manipulamos datos es la aparición de acentos propios del idioma español correctamente escrito. Como la mayoría de los juegos de caracteres están basados en Unicode, práctimente podemos encontrar símbolos de casi cualquier lengua.
Con nuestro idioma español seteado (parámetro NLS_LANGUAGE), podemos comprobar que 'Á' es mayor que 'á':
SQL> select greatest('Á','á') from dual;
GR
--
Á
A su vez 'á' es mayor que 'a':
SQL> select greatest('á','a') from dual;
GR
--
á
Luego 'a' es mayor que 'A'
SQL> select greatest('A','a') from dual;
G
-
a
Pasando en limpio tenemos que: Á > á > a > A
Para evitar estos problemas de orden de los caracteres con acentos (incluímos la ñ y Ñ) dentro de la plantilla de caracteres, nos conviene traducir estos caracteres a un solo formato en mayúscula y desasentuado (despues de todo para ordenar no nos importan estas diferencias).
La función TRANSLATE viene como anillo al dedo para esta necesaria conversión de caracteres. La sintáxis básica es: TRANSLATE(cadena
Lo aplicaremos así:
UPPER(TRANSLATE(
SQL> SELECT UPPER(TRANSLATE('HABÍAn relámpagos','ÁÉÍÓÚáéíóú','AEIOUAEIOU'
)) TEXTO FROM DUAL;
TEXTO
-----------------
HABIAN RELAMPAGOS
Es aconsejable tener un paquete con una función que reciba una cadena, aplique estas funciones de conversión y retorne la cadena desacentuada. Evitará reescribir código y además tendremos la función cacheada en memoria para las siguientes invocaciones.
UPPER/TRANSLATE podrá usarse en SQL para comparar cadenas, con el cuidado necesario para evitar anular índices por el uso de funciones. Es necesario evaluar el alterar los datos almacenados de forma de eliminar la acentuación, o crear índices de función que estén definidos con la funcion de conversión. Dependerá de cada caso particular que es lo más conveniente.
Ver también:
Como detectar caracteres extraños o no imprimibles
jueves 25 de octubre de 2007
Acentos del idioma español
martes 23 de octubre de 2007
Update condicional
¿Cómo se hace un UPDATE condicional?
Digamos que tengo una tabla t con 3 campos a, b y c. Quiero que si a=1 entonces actualizo b con algún valor, y si a=2 actualizo c.
Alguien de mi equipo se encontró con este dilema y lo resolvió de forma muy práctica: dos updates, uno para actualizar aquellos valores con a=1 y otro para actualizar los a=2:
1 BEGIN
2 UPDATE t
3 SET b=valor
4 WHERE a=1;
5
6 UPDATE t
7 SET c=valor
8 WHERE a=2;
9 END;
Otro programador del equipo refutó: -¿Para qué ejecutar dos sentencias update si en su lugar puedes hacer una?
1 BEGIN
2 UPDATE t
3 SET B=DECODE(A,1,valor
4 C=DECODE(A,1,C,2,
5 END;
¿Quién de los dos tiene razón?
...depende.
Dado que la performance parece ser lo que está en juego, la primera pregunta que cabe es:
¿Tiene la tabla t índice por A?
Si la tabla no tiene índice, entonces debemos recorrerla por entero. En el primer caso recorremos la tabla dos veces, mientras que en el segundo caso lo hacemos solamente una! Por lo tanto la primera solución en este escenario es el doble más lenta que la segunda. Al notar que la tabla no tiene índices, el Programador 2 asiente la cabeza con orgullo.
Inmediatamente el Programador 1 reacciona: -Pongámosle un índice a t entonces!
(el ávido Programador 1 sabe que la segunda consulta no puede sacar provecho de un índice por lo que su victoria parece asegurada)
Y aquí es donde cabe la segunda pregunta:
¿Cuál es la cardinalidad de la columna A?
Sería de gran ayuda saber si 1 y 2 son la mayoría de los valores que hay en la columna A, porque en ese caso, el optimizador va a continuar prefiriendo recorrer toda la tabla! Si la cardinalidad de los valores 1 y 2 son un porcentaje muy bajo del conjunto de valores distintos, entonces recién ahí los índices van a ser utilizados.
Cuando el índice es utilizado por la escasa presencia de valores 1 y 2, los tiempos de la primer solución es abismalmente inferior.
Conclusión:
La solución 1 es mejor si existen índice sobre la columna A y su cardinalidad es alta (hay pocos 1 y 2 en A).
La solución 2 es mejor si no existen índices o existe y la cardinalidad de A es baja para valores 1 y 2 (significa que 1 y 2 ocurren mucho en A).
Ver también:
Mis índices no funcionan!
Indices condicionales
