Optimizando un SELECT que compara columnas de la misma tabla

3 comentarios

En general, debemos tener a todas las columnas de todas nuestras tablas normalizadas. Eso es lo correcto y es lo recomendable. Sin embargo, hay ocasiones en que desnormalizar las columnas es conveniente.

Una de esas ocasiones es cuando debemos escribir un SELECT que en la cláusula WHERE compara el contenido de dos columnas. Veamos un ejemplo.

Tenemos la tabla PRODUCTOS con la siguiente estructura:

optimizando1

Captura 1. Si haces clic en la imagen la verás más grande

Y queremos saber si hay productos cuyo precio de venta es menor que su precio de costo, así que escribimos el siguiente SELECT.

Listado 1.

SELECT
   *
FROM
   PRODUCTOS
WHERE
   PRD_PREVTA < PRD_PRECTO

La consulta nos mostrará el resultado correcto, pero si analizamos su rendimiento, encontraremos que no ha usado un índice.

optimizando2

Captura 2. Si haces clic en la imagen la verás más grande

El problema es que no podemos tener un índice que pueda ser usado en casos como este. O sea, que no podemos tener índices para:

  • Comparar dos columnas de la misma tabla por =
  • Comparar dos columnas de la misma tabla por <
  • Comparar dos columnas de la misma tabla por >
  • Comparar dos columnas de la misma tabla por <=
  • Comparar dos columnas de la misma tabla por >=
  • Comparar dos columnas de la misma tabla por <>

Si la tabla tiene pocas filas, eso no es un problema, Firebird es muy rápido para devolver el resultado de los SELECT. Pero si la tabla tiene muchas filas, allí ya es otro tema.

¿Y cómo podemos hacer para mejorar la velocidad de nuestro SELECT?

La solución es crear una columna que contenga la diferencia entre las dos columnas que nos interesan. La estructura de la tabla PRODUCTOS quedaría entonces así:

optimizando3

Captura 3. Si haces clic en la imagen la verás más grande

Para mantener actualizada a la columna PRD_DIFERE podríamos escribir un trigger como el siguiente:

Listado 2.

CREATE TRIGGER PRODUCTOS_BIU FOR PRODUCTOS
   ACTIVE BEFORE
   INSERT OR
   UPDATE
   POSITION 1
AS
BEGIN

   NEW.PRD_DIFERE = NEW.PRD_PREVTA - NEW.PRD_PRECTO;

END;

Y para usar un índice entonces deberemos crearlo.

Listado 3.

CREATE INDEX IDX_PRODUCTOS ON PRODUCTOS(PRD_DIFERE);

Y si ahora escribimos el SELECT del Listado 1. modificado para que utilice a la columna PRD_DIFERE, tendríamos:

Listado 4.

SELECT
   *
FROM
   PRODUCTOS
WHERE
  PRD_DIFERE < 0

Queremos verificar si ahora se está usando un índice, así que miramos el rendimiento y encontramos:

optimizando4

Captura 4. Si haces clic en la imagen la verás más grande

Y comprobamos que sí, efectivamente ahora se usa un índice, y por lo tanto nuestro SELECT será mucho más rápido que antes.

Conclusión:

En general debemos tener a todas las columnas de todas nuestras tablas normalizadas, pero hay excepciones, como el caso mostrado en este artículo. Eso se debe a que el Firebird no utiliza índices cuando comparamos el contenido de una columna con el contenido de otra columna. La solución es crear una columna adicional que contendrá la diferencia entre los valores de las columnas que necesitamos comparar.

Desde luego que comparar precio de costo con precio de venta es sólo un ejemplo. También podemos comparar importe vendido contra importe cobrado, importe comprado contra importe pagado, etc.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Anuncios

Usando Database Comparer en línea de comandos

4 comentarios

En el artículo:

https://firebird21.wordpress.com/2013/06/10/database-comparer-de-clever-components/

ya habíamos hablado sobre un programa muy bueno para comparar bases de datos llamado Database Comparer, de la empresa Clever Components.

Pues bien, ese programa además de permitirnos interactuar con él por medio del GUI (Graphical User Interface) también nos permite ejecutarlo a través de la línea de comandos, como veremos ahora.

¿Y para qué nos serviría ejecutarlo a través de la línea de comandos?

La utilidad más normal de esta característica es que podemos automatizar el proceso en nuestra aplicación (o sea, en el archivo .EXE que nosotros creamos y que los usuarios ejecutan).

En nuestro .EXE podemos hacer que la comparación (y actualización, si es necesaria) se haga en forma automática o cuando el usuario haga clic sobre algún botón.

Veamos la situación:

Estamos desarrollando un sistema de contabilidad que será usado por muchos estudios contables. Un estudio contable normalmente lleva la contabilidad de muchos clientes. Como sabemos que no es bueno tener en una sola Base de Datos a todos los clientes del estudio contable sino que lo recomendable es que cada uno de sus clientes tenga su propia Base de Datos nos encontramos con un problema.

¿Cuál es el problema?

Que la estructura de una Base de Datos (es decir, sus metadatos) no es fija, por mucho que la hayamos analizado siempre cabe la posibilidad de que alguna vez debamos crear una tabla, o modificar una existente, agregarle índices, vistas, stored procedures, triggers, etc.

Si el estudio contable solamente tuviera uno o dos clientes sería muy sencillo. Con la GUI de Database Comparer en un ratito actualizaríamos las bases de datos y listo, a otra cosa.

Pero lo normal es que los estudios contables tengan decenas o centenas de clientes, y allí la actualización manual ya se vuelve muy impráctica, demora mucho tiempo, y existe la gran posibilidad de no actualizar todas las bases de datos o hacerlo de manera equivocada (actualizando al revés), con la consecuencia de que podrían perderse muchos datos y todos los trastornos que eso ocasionaría.

El comportamiento adecuado

Ante una situación como la antedicha, ¿qué es lo mejor?

  1. Creamos una Base de Datos vacía, modelo, que solamente tiene los metadatos. Por ejemplo la llamamos MASTER.FDB
  2. Por cada cliente del estudio contable tenemos una Base de Datos que cuando se agregó ese cliente simplemente se copió físicamente a MASTER.FDB para tener la Base de Datos del cliente. Así podríamos tener ALICIA.FDBGRACIELA.FDB, SUSANA.FDB, etc., las cuales inicialmente eran una simple copia de MASTER.FDB y después se les fueron agregando los datos que les correspondían.
  3. Cuando debemos cambiar algo en la Base de Datos, la única Base de Datos que tocamos, la única con la cual trabajamos es MASTER.FDB
  4. Cuando el usuario abre una Base de Datos, nuestro programa .EXE compara la versión de MASTER.FDB con la versión de la Base de Datos que él abrió. Por ejemplo, si abrió GRACIELA.FDB se compara a MASTER.FDB con GRACIELA.FDB
  5. Para comparar a ambas bases de datos lo mejor es que tengan una tabla, por ejemplo llamada VERSION con una columna llamada por ejemplo VER_NUMERO. Si el número de versión de MASTER.FDB es más nuevo que el número de versión de GRACIELA.FDB entonces estamos seguros de que GRACIELA.FDB debe ser actualizada
  6. Si descubrimos que GRACIELA.FDB debe ser actualizada, entonces nuestro programa .EXE ejecuta a Database Comparer con sus parámetros de la línea de comandos
  7. De esta manera, no importa si el estudio contable tiene cientos de bases de datos, cada vez que el usuario abra una de esas bases de datos se la comparará con MASTER.FDB y en el caso de que la versión de MASTER.FDB sea más nueva entonces se actualizará la Base de Datos que el usuario abrió.
  8. Y estaremos seguros de que sea cual sea la Base de Datos que el usuario abra, y aunque hayan pasado meses o años desde la última vez que la abrió, siempre estará correctamente actualizada.
  9. Lo único que debemos recordar es que cada vez que cambiamos algo en MASTER.FDB debemos actualizar la columna VER_NUMERO de la tabla VERSION, escribiendo un número que sea mayor que el que existía ahí.

La interfaz de línea de comandos de Database Comparer

Si abrimos una ventanita “Símbolo del sistema”, nos ubicamos en una carpeta donde se encuentre el programa DBCOMPARER.EXE y lo ejecutamos con la opción /? veremos las opciones disponibles.

DBCOMPARER

Captura 1. Si haces clic en la imagen la verás más grande

Ejemplo de uso

Al programa DBCOMPARER.EXE podemos copiarlo en cualquier carpeta, no es necesario ni obligatorio ejecutarlo en la carpeta donde fue instalado. Lo mejor generalmente es copiar a DBCOMPARER.EXE y al archivo IBDB_CMP.CFG (donde se guardan los alias, las ubicaciones de las bases de datos, etc.) a la misma carpeta donde se encuentra nuestro programa .EXE

DBCOMPARER2

Captura 2. Si haces clic en la imagen la verás más grande

Al escribir el comando anterior lo que hacemos es decirle a DBCOMPARER que compare a la Base de Datos cuyo alias en ese programa es MASTER con la Base de Datos cuyo alias en ese programa es PRUEBA1. Si hay diferencias entonces PRUEBA1 cambiará para que sus metadatos sean idénticos a los metadatos de MASTER.

Cuando el programa finalice, estaremos seguros de que ambas bases de datos tienen exactamente la misma estructura.

Conclusión:

Database Comparer es una muy buena aplicación para comparar las estructuras de las bases de datos y para hacer que sean idénticas en caso de que tengan diferencias.

Si las bases de datos a comparar son pocas, el proceso puede ser realizado manualmente, es muy sencillo, nada complicado.

Pero si las bases de datos son muchas, entonces hacerlo manualmente demorará mucho tiempo y además se corre el riesgo de no compararlas a todas o de compararlas en el sentido erróneo. Por lo tanto es mucho mejor automatizar ese proceso.

La interfaz de línea de comandos justamente nos permite automatizar la comparación y actualización. Por eso, es conveniente usarla.

Enlaces:

http://www.clevercomponents.com/products/dbcomparer/index.asp

http://www.clevercomponents.com/products/index.asp

http://www.clevercomponents.com/downloads/index.asp

Artículos relacionados:

Database Comparer de Clever Components

El índice del blog Firebird21

El foro del blog Firebird21

Usando SIMILAR TO

2 comentarios

Los predicados de comparación son muy útiles cuando queremos buscar columnas que cumplen con alguna condición, como hemos visto aquí:

https://firebird21.wordpress.com/2014/04/27/los-predicados-de-comparacion/

De todos ellos, el más poderoso es SIMILAR TO.

Pero justamente por ser el más poderoso es también el más complicado para entenderlo y para obtener de él el máximo provecho.

Caracteres especiales

Cuando usamos SIMILAR TO hay algunos caracteres que tienen un significado especial, y son los siguientes:

[ ] ( ) | ^ – + * % _ ? { }

y también el carácter de escape, si el carácter de escape fue definido.

Caracteres comunes

Si no hay caracteres especiales ni carácter de escape entonces SIMILAR TO funciona igual que el operador “=”

'NAPOLEON' SIMILAR TO 'NAPOLEON'               -- Verdadero
'NAPOLEON BONAPARTE' SIMILAR TO 'NAPOLEON'     -- Falso
'NAPOLEON' SIMILAR TO 'NAPOLEON BONAPARTE'     -- Falso
'NAPOLEON' SIMILAR TO 'Napoleón'               -- Puede ser, depende del COLLATE utilizado

Comodines

Se puede usar el comodín _ que reemplaza a un carácter cualquiera, y el comodín % que reemplaza a cualquier cantidad de caracteres.

'NAPOLEON' SIMILAR TO 'N_POLEON'         -- Verdadero
'NAPOLEON' SIMILAR TO 'N_LEON'           -- Falso
'NAPOLEON' SIMILAR TO 'N%LEON'           -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO%LEON%'       -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOOO%LEON'      -- Falso
'NAPOLEON' SIMILAR TO 'NAPOOO%LEON%'     -- Falso

El primer caso es verdadero porque el segundo caracter podía ser cualquiera, incluyendo por supuesto a una A

El segundo caso es falso porque el guión bajo reemplaza a solamente un caracter y allí faltarían dos más

El tercer caso es verdadero porque el % reemplaza a cualquier cantidad de caracteres

El cuarto caso es verdadero porque el % también reemplaza al string vacío

El quinto caso es falso porque hay dos letras O sobrantes

El sexto caso es falso porque hay dos letras O sobrantes

Clases de caracteres

Un grupo de caracteres rodeados por corchetes se llama clase de caracteres. Hay coincidencia cuando un carácter, y solamente uno, de los que están rodeados por corchetes es igual.

'NAPOLEON' SIMILAR TO 'NAPO[LMN]EON'           -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[LE]ON'             -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[LMN][AEIOU]ON'     -- Verdadero

El primer caso es verdadero porque la L se encuentra en la clase.

El segundo caso es falso porque solamente se puede usar un carácter de la clase y en este caso se necesitaría de dos.

El tercer caso es verdadero porque de la primera clase se extrae la L y de la segunda clase se extrae la E.

Rangos

Usar clases de caracteres es muy conveniente pero cuando los caracteres son muchos puede ser muy tedioso escribirlos a todos. Por eso se pueden usar rangos. Los rangos están compuestos por un carácter inicial, un guión, y un carácter final. Todos los caracteres que se encuentren entre ese carácter inicial y ese carácter final, ambos incluidos, estarán dentro de la clase.

'NAPOLEON' SIMILAR TO 'NAPO[J-R]EON'           -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[RSK-PXYZ]EON'      -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[AF-JM-SZ]EON'      -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[AF-JLM-SZ]EON'     -- Verdadero

El primer caso es verdadero porque la L está entre las letras J y R.

El segundo caso es verdadero porque la L está entre las letras K y P.

El tercer caso es falso porque la L no está entre la F y la J, tampoco entre la M y la S, y tampoco se la ve en la clase

El cuarto caso es verdadero porque se ve a la L en la clase

Clases predefinidas

Hay algunas clases de caracteres que se utilizan muy frecuentemente entonces están predefinidas, para facilitarnos la vida. Son las siguientes:

[:ALPHA:]

Letras inglesas dentro de los rangos a .. z y A .. Z. Si se utiliza un COLLATE que sea CI entonces también incluye a las vocales acentuadas.

[:DIGIT:]

Los dígitos 0 .. 9

[:ALNUM:]

La unión de [:ALPHA:] con [:DIGIT:]

[:UPPER:]

Letras mayúsculas en el rango A .. Z. También coincide cuando las letras son minúsculas y el COLLATE es CI o es AI

[:LOWER:]

Letras minúsculas en el rango A .. Z. También coincide cuando las letras son mayúsculas y el COLLATE es CI o es AI

[:SPACE:]

El espacio en blanco (código ASCII 32)

[:WHITESPACE:]

Tabulador vertical (código ASCII 9), alimentador de línea (código ASCII 10), tabulador horizontal (código ASCII 11), alimentación de página (código ASCII 12), retorno del carro (código ASCII 13), y espacio en blanco (código ASCII 32).

Usar una clase predefinida es lo mismo que usar todos sus miembros. Las clases predefinidas pueden ser usadas solamente dentro de una definición de clases. Si necesitas verificar la coincidencia contra una clase predefinida y nada más, entonces debes usar dos pares de corchetes.

'NAPOLEON' SIMILAR TO 'NAPO[[:ALPHA:]]EON'      -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[[:DIGIT:]]EON'      -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[L[:DIGIT:]]EON'     -- Verdadero
'NAPOLEON' SIMILAR TO '[[:ALPHA:]]'             -- Falso
'N' SIMILAR TO '[[:ALPHA:]]'                    -- Verdadero

El primer caso es verdadero porque la letra L está incluida en la clase predefinida [:ALPHA:]

El segundo caso es falso porque la letra L no está incluida en la clase predefinida [:DIGIT:]

El tercer caso es verdadero porque la L está dentro de la clase

El cuarto caso es falso porque de la clase predefinida [:ALPHA:] solamente se puede usar una letra y NAPOLEON tiene 8 letras

El quinto caso es verdadero porque la letra N está incluida dentro de la clase predefinida [:ALPHA:]

Acento circunflejo

Si se usa un acento circunflejo pueden darse dos casos:

  1. La clase empieza con un acento circunflejo. Siendo así todos los caracteres siguientes son excluidos de la clase
  2. La clase no empieza con un acento circunflejo. Siendo así la clase contiene todos los caracteres anteriores, excepto por los caracteres que se encuentren también después del acento circunflejo
'NAPOLEON' SIMILAR TO 'NAPO[^L]EON'              -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[^A-M]EON'            -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[^A-EL]EON'           -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[^[:DIGIT:]]LEON'     -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[A-M^R-V]EON'         -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[A-M^J-S]EON'         -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-M^L]EON'           -- Falso

 El primero caso es falso porque se excluye a la L

El segundo caso es falso porque se excluye a todos los caracteres que están en el rango A .. M

El tercer caso es falso porque se excluye a todos los caracteres que están en el rango A .. E y también a la L

El cuarto caso es verdadero porque se excluye solamente a los dígitos

El quinto caso es verdadero porque se incluye a todos los caracteres entre A .. M y se excluye a los que están entre R .. V, y la L se encuentra entre los incluidos

El sexto caso es falso porque la L se incluye en el rango A .. M pero se la excluye en el rango J .. S y la exclusión tiene preferencia

El séptimo caso es falso porque la L está en el rango A .. M pero específicamente se la excluye después

Cuantificadores

 Los cuantificadores son los siguientes: ? * +

Además de números encerrados entre llaves

Y los usamos para indicar la cantidad de veces que queremos que se repitan los caracteres

El ? indica que el carácter o clase que le antecede debe ocurrir 0 ó 1 vez

'NAPOLEON' SIMILAR TO 'NAPO?LEON'               -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOX?LEON'              -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOXX?LEON'             -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-M]?EON'           -- Verdadero
'NAPOLEON' SIMILAR TO 'N[A-E]?POLEON[R-Z]?'     -- Verdadero

El primer caso es verdadero porque la letra O se encuentra 0 ó 1 vez

El segundo caso es verdadero porque la letra X se encuentra 0 ó 1 vez

El tercer caso es falso porque la letra X se encuentra 2 veces, y debería encontrarse 0 ó 1 vez para ser verdadero

El cuarto caso es verdadero porque la letra L se encuentra una vez en el rango A .. M

El quinto caso es verdadero porque la letra A se encuentra una vez en el rango A .. E y las letras R .. Z se encuentran 0 veces después de POLEON

El * indica que el carácter o clase que le antecede puede ocurrir 0, 1 ó muchas veces

'NAPOLEON' SIMILAR TO 'NAPO*LEON'               -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOX*LEON'              -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOXX*LEON'             -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-M]*EON'           -- Verdadero
'NAPOLEON' SIMILAR TO 'N[A-E]*POLEON[R-Z]*'     -- Verdadero

El primer caso es verdadero porque la letra O se encuentra 0, 1, ó más veces

El segundo caso es verdadero porque la letra X se encuentra 0, 1, ó más veces

El tercer caso es falso porque la letra X se encuentra 2 veces, y debería encontrarse 0 ó 1 vez para ser verdadero

El cuarto caso es verdadero porque la letra L se encuentra una vez en el rango A .. M

El quinto caso es verdadero porque la letra A se encuentra una vez en el rango A .. E y las letras R .. Z se encuentran 0 veces después de POLEON

El + indica que el carácter o clase que le antecede debe ocurrir 1 vez ó más de 1 vez. O sea que es obligatorio que ocurra.

'NAPOLEON' SIMILAR TO 'NAPO_+'                  -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO+LEON'               -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPOLEONX+'              -- Falso
'NAPOLEON' SIMILAR TO 'NAPO[A-P]+EON'           -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO[[:DIGIT:]]+EON'     -- Falso

 El primer caso es verdadero porque el carácter anterior al + puede ser cualquiera, y ocurrió una vez

El segundo caso es verdadero porque la letra O ocurrió una vez

El tercer caso es falso porque la letra X no ocurrió ni una vez

El cuarto caso es verdadero porque la letra L se encuentra en el rango A .. P y ocurrió una vez

El quinto caso es falso porque se necesitaba una letra L pero en su lugar hay dígitos

Si un carácter o una clase son seguidos por un número rodeado por llaves, ese carácter o esa clase deben repetirse exactamente ese número de veces

'NAPOLEON' SIMILAR TO 'NAPO{2}LEON'               -- Falso
'NAPOLEON' SIMILAR TO 'NAPO{1}LEON'               -- Verdadero
'NAPOLEON' SIMILAR TO 'NAP[[:ALPHA:]]{1}LEON'     -- Verdadero
'NAPOLEON' SIMILAR TO 'NAP[[:ALPHA:]]{2}LEON'     -- Falso
'NAPOLEON' SIMILAR TO 'NA[M-R]{2}LEON'            -- Verdadero

El primer caso es falso porque la letra O debería estar 2 veces y está solamente 1 vez

El segundo caso es verdadero porque la letra O está 1 vez

El tercer caso es verdadero porque la letra O está incluida una vez en la clase predefinida [:ALPHA:]

El cuarto caso es falso porque la letra O está incluida una vez en la clase predefinida [:ALPHA:] y se está pidiendo que esté incluida dos veces

El quinto caso es verdadero porque la letra P está incluida una vez en el rango M .. R y la letra O está incluida una vez en ese rango, por lo tanto son 2

Si el número es seguido por una coma, entonces el carácter o la clase que le preceden deben repetirse al menos ese número de veces

'NAPOLEON' SIMILAR TO 'NAPO{1,}LEON'     -- Verdadero
'NAPOLEON' SIMILAR TO 'NAPO{2,}LEON'     -- Falso
'NAPOLEON' SIMILAR TO 'NA[E-S]{3,}'      -- Verdadero
'NAPOLEON' SIMILAR TO 'NA[F-S]{3,}'      -- Falso

El primer caso es verdadero porque la letra O se repite una vez o más

El segundo caso es falso porque la letra O no se repite dos veces o más

El tercer caso es verdadero porque los caracteres del rango E .. S se repiten 3 veces o más

El cuarto caso es falso porque la letra E no está en el rango

Si dentro de las llaves hay dos números separados por comas, siendo el segundo mayor o igual que el primero, entonces el carácter o la clase que le preceden deben repetirse al menos el primer número y como máximo, el segundo número

'NAPOLEON' SIMILAR TO 'NA[E-S]{2,3}'     -- Falso
'NAPOLEON' SIMILAR TO 'NA[E-S]{2,6}'     -- Verdadero
'NAPOLEON' SIMILAR TO 'NA[E-S]{4,6}'     -- Verdadero

El primer caso es falso porque las letras E .. S se repiten 6 veces y deberían repetirse como máximo 3 veces

El segundo caso es verdadero porque las letras E .. S se repiten 6 veces, y deberían repetirse entre 2 y 6 veces

El tercer caso es verdadero porque las letras E .. S se repiten 6 veces y deberían repetirse entre 4 y 6 veces

La disyunción se realiza con el operador | y es verdadera cuando hay coincidencia con alguno de los dos ítems

'NAPOLEON' SIMILAR TO 'NAPO|LEON'              -- Falso
'NAPOLEON' SIMILAR TO 'NAPOLEON|BONAPARTE'     -- Verdadero
'NAPOLEON' SIMILAR TO 'MAR_+|NA_+|TUZ_+'       -- Verdadero

El primer caso es falso porque NAPOLEON no es igual a NAPO y tampoco es igual a LEON

El segundo caso es verdadero porque NAPOLEON es igual a NAPOLEON

El tercer caso es verdadero porque NA_+ es verdadero

Subexpresiones

Puedes utilizar subexpresiones si las rodeas con paréntesis.

'NAPOLEON' SIMILAR TO 'NA(PA|PE|PI|PO|PU)LEON'     -- Verdadero
'NAPOLEON' SIMILAR TO 'NA(P[M-R]+)LEON'            -- Verdadero
'NAPOLEON' SIMILAR TO 'NA([M-R]{2})LEON'           -- Verdadero

El primer caso es verdadero porque PO está incluido en la subexpresión

El segundo caso es verdadero porque PO está incluido en la subexpresión

El tercer caso es verdadero porque PO está incluido en la subexpresión

Caracteres especiales de escape

Para que la comparación pueda ser hecha contra un carácter que se usa dentro de los patrones de caracteres, ese carácter debe ser “escapado”.

'NAPOLEON (FRANCIA)' SIMILAR TO 'N[^ ]+ \(F[^ ]+\)' ESCAPE '\'     -- Verdadero

Este caso es verdadero porque se está verificando que empiece con N, que luego haya un espacio en blanco, un paréntesis abierto, una letra F, y un paréntesis cerrado.

Conclusión:

El predicado de comparación SIMILAR TO es el más poderoso de todos los predicados de comparación pero así también es el más difícil de entender y de usar completamente.

Sin embargo, bien que vale la pena el esfuerzo porque si dominas el uso de SIMILAR TO entonces tus comparaciones que involucren a strings serán muy rápidas, muy eficientes, y mucho más cortas de escribir que si debes hallar los mismos resultados sin usar SIMILAR TO.

Artículos relacionados:

Los predicados de comparación

El índice del blog Firebird21

El foro del blog Firebird21

 

Database Comparer de Clever Components

3 comentarios

Normalmente cuando desarrollamos nuestras aplicaciones trabajamos en una computadora y con una Base de Datos local. Luego, cuando la aplicación está operativa la instalamos en las computadoras de nuestros clientes, junto con la Base de Datos respectiva.

Pero como las aplicaciones no son estáticas es frecuente que debamos realizar algunos cambios en ellas y también en las bases de datos a las cuales se conectan. Por lo tanto podemos considerar que tenemos dos bases de datos:

  • De desarrollo (la que utilizamos para nuestras pruebas)
  • De producción (la que utilizan los usuarios de nuestra aplicación)

Los cambios en los metadatos (dominios, tablas, índices, stored procedures, triggers, etc.) los hacemos en la Base de Datos de desarrollo y luego queremos que la Base de Datos de producción tenga esos mismos metadatos.

Por ejemplo, si en la Base de Datos de desarrollo a la tabla PRODUCTOS le agregamos una columna llamada PRD_CANMAX (cantidad máxima que podemos tener de ese producto) que definimos como SMALLINT, también queremos que en la tabla PRODUCTOS de la Base de Datos de producción tengamos esa misma columna.

O sea que:

Todos los cambios que hagamos en la Base de Datos de desarrollo se reflejen en la Base de Datos de producción

Hay varias formas de realizar esa tarea, podemos hacerla manualmente (anotando todos y cada uno de los cambios que hacemos en la Base de Datos de desarrollo y luego hacer esos mismos cambios en la Base de Datos de producción), usando scripts, usando programas especializados.

En este artículo veremos como usar uno de esos programas especializados, su nombre es “Database Comparer”, de “Clever Components” y es gratis para uso no comercial.

Podemos leer su descripción (en inglés) aquí:

http://www.clevercomponents.com/products/dbcomparer/index.asp

Y podemos descargarlo desde aquí:

http://www.clevercomponents.com/downloads/dbc/index.asp

DATABASECOMPARER1

(haciendo clic en la imagen la verás más grande)

DATABASECOMPARER2

(haciendo clic en la imagen la verás más grande)

Como puedes ver en la imagen de arriba, viene en dos versiones: para computadoras de 32 bits y para computadoras de 64 bits. Por supuesto, elige el que corresponda a los bits de la computadora donde lo instalarás.

 Alternativamente, podemos descargarlo desde aquí:

http://www.mediafire.com/download/6au956m6adk6aes/DatabaseComparer.exe

Luego de instalarlo, al ejecutarlo veremos esta pantalla:

DATABASECOMPARER3

(haciendo clic en la imagen la verás más grande)

 Y luego de unos segundos, esta pantalla:

DATABASECOMPARER4

(haciendo clic en la imagen la verás más grande)

Database Comparer nos permite comparar las bases de datos de varios motores SQL (Firebird, Interbase, Sybase, MS SQL, MySQL). Para decirle que queremos comparar bases de datos de Firebird debemos elegir la pestaña IB/FB

DATABASECOMPARER5

(haciendo clic en la imagen la verás más grande)

 Y luego, la versión del Firebird de nuestras bases de datos:

DATABASECOMPARER6

(haciendo clic en la imagen la verás más grande)

 ¿Cómo funciona Database Comparer?

Comparando dos bases de datos: Master (la que tiene los metadatos actualizados) y Target (la que será actualizada). Por lo tanto, Master es nuestra Base de Datos de desarrollo y Target es la Base de Datos de producción (la que usan los usuarios de nuestra aplicación).

A ambas bases de datos debemos asignarles alias, o sea nombres alternativos. Eso lo hacemos eligiendo en el menú la opción “Database” y luego la opción “New database alias…” o haciendo clic en el icono respectivo

DATABASECOMPARER7

(haciendo clic en la imagen la verás más grande)

A continuación verás una ventana similar a la siguiente:

DATABASECOMPARER10

(haciendo clic en la imagen la verás más grande)

 Debes escribir:

  • El alias que deseas para tu Base de Datos (en este ejemplo el alias es DESARROLLO, pero tú puedes elegir cualquier otro)
  • El tipo de Base de Datos (debe ser “Interbase/FB” para Firebird)
  • La versión del Firebird (en este ejemplo es 2.5)
  • El protocolo (en este ejemplo es TCP/IP)
  • El puerto que utiliza el Servidor del Firebird (normalmente es 3050 pero en este ejemplo es 3051)
  • La ruta y el nombre completos de tu Base de Datos
  • La ruta y el nombre completo de la librería cliente (el archivo fbclient.dll)
  • El nombre del usuario (en este caso es SYSDBA)
  • La contraseña de este usuario (está oculta)

Luego, debes hacer clic en el botón “Test connect” para verificar que pueda conectarse a esa Base de Datos.

Si la conexión tuvo éxito verás algunas características de tu Base de Datos y al final la palabra “Passed”. Si por algún motivo falló la conexión entonces verás la palabra “Failed”.

A continuación, debes repetir todos esos pasos para crear el alias de la otra Base de Datos, como puedes ver en la siguiente captura de pantalla:

DATABASECOMPARER11

(haciendo clic en la imagen la verás más grande)

 En este caso el nombre del alias es “PRODUCCION”. Como se trata de otra Base de Datos también se cambió el valor de “Database name”. Recuerda que son dos bases de datos las que quieres comparar: la de desarrollo y la de producción. La de desarrollo inclusive podrías tenerla en un pen-drive.

A continuación, hay que especificar cual de esos alias se usará como Master y cual se usará como Target.

DATABASECOMPARER12

(haciendo clic en la imagen la verás más grande)

 Como puedes ver, a la izquierda tenemos los alias, a continuación de Master se eligió el alias que le corresponde a la Base de Datos que tiene los metadatos actualizados y a continuación de Target se eligió el alias que le corresponde a la Base de Datos que será actualizada. A la derecha el programa nos mostró la ubicación y el nombre de esas bases de datos (rodeadas con un óvalo azul).

Una vez que ya especificamos los alias y se los asignamos a Master y a Target el siguiente paso es comparar ambas bases de datos para encontrar las diferencias que hay entre ellas. Eso lo hacemos con el icono “Compare databases”

DATABASECOMPARER13

(haciendo clic en la imagen la verás más grande)

 El programa empezará a trabajar, generará scripts para ambas bases de datos, comparará dichos scripts y luego nos dirá si es necesaria la actualización.

DATABASECOMPARER14

(haciendo clic en la imagen la verás más grande)

Si vemos las palabras “Need Update” entonces sí se necesita actualizar el Target.

Para actualizarlo, hacemos clic en el botón “Execute script”

DATABASECOMPARER15

(haciendo clic en la imagen la verás más grande)

Si encontró algunos errores y por lo tanto no pudo actualizar el Target veremos un mensaje como este al final.

DATABASECOMPARER16

 (haciendo clic en la imagen la verás más grande)

Y en este caso hay que buscar los errores y corregirlos.

En cambio, si la actualización se realizó con éxito veremos algo así:

DATABASECOMPARER17

 (haciendo clic en la imagen la verás más grande)

 El mensaje “Script executed succesfully!” significa: “El script de actualización se ha ejecutado exitosamente”.

Y en consecuencia: la Base de Datos de producción ya tiene los metadatos idénticos a la Base de Datos de desarrollo.

Resumen:

Database Comparer de Clever Components nos permite comparar dos bases de datos para saber si sus metadatos son iguales o son diferentes. Y en caso de que sean diferentes puede actualizar a la Base de Datos que especificamos como Target para que sea idéntica a la Base de Datos que especificamos como Master.

Importante:

Aunque no es requerido, siempre es una muy buena idea hacer un backup de la Base de Datos de producción (esa donde los usuarios ingresan sus datos) antes de compararla y actualizarla. Así, si algo llegara a salir mal, siempre tendremos la posibilidad de restaurarla a su estado anterior.

Observación:

Metadatos se refiere al contenido interno de la Base de Datos (dominios, tablas, índices, stored procedures, triggers, generadores, excepciones, etc.) o sea lo que escriben los desarrolladores, no son los datos de los usuarios.