Ejemplo de recursión (4). Actualizando filas recursivamente

3 comentarios

Así como podemos consultar filas de forma recursiva, también podemos actualizar esas filas recursivamente si es lo que necesitamos.

Veamos un caso:

Tenemos una tabla llamada CUENTAS que tiene estos datos:

UPDATE1

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

En la columna CUE_IDENTI guardamos el identificador de cada fila; en la columna CUE_IDEPAD guardamos el identificador de su fila padre; en la columna CUE_TIMEST guardamos la fecha y la hora de la última actualización de una cuenta. Ahora supongamos que queremos que la cuenta CRÉDITOS y todas las cuentas que sean sus descendientes tengan la fecha y la hora actuales.

Listado 1.

UPDATE
   CUENTAS
SET
   CUE_TIMEST = CURRENT_TIMESTAMP
WHERE
   CUE_IDENTI IN (
      WITH RECURSIVE MiCTE AS (
         
         SELECT
            CUE_IDENTI
         FROM
            CUENTAS
         WHERE
            CUE_IDENTI = 6
         
         UNION ALL
         
         SELECT
            T1.CUE_IDENTI
         FROM
            CUENTAS T1
         JOIN
            MiCTE 
               ON T1.CUE_IDEPAD = MiCTE.CUE_IDENTI
         
      )
      
      SELECT CUE_IDENTI FROM MiCTE

   );

UPDATE2

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

Tal y como podemos ver en la Captura 2. se actualizó la columna CUE_TIMEST de la cuenta que tiene CUE_IDENTI =6 y también de todos sus descendientes. En el Listado 1. podemos ver que la primera cuenta a ser actualizada es la que tiene CUE_IDENTI = 6, a continuación se actualizan las demás filas.

Desde luego que no solamente podemos cambiar la fecha y la hora al actualizar, podemos cambiar cualquier dato que necesitemos.

Explicación:

Como en la cláusula WHERE del UPDATE estamos usando IN eso significa que queremos actualizar varias filas. ¿Qué filas actualizaremos? Aquellas cuya columna CUE_IDENTI se encuentre en la tabla virtual que crearemos. En nuestra tabla virtual la primera fila es la que tiene CUE_IDENTI = 6, así que esa fila sí o sí será actualizada. A continuación hallamos el CUE_IDENTI de las demás filas que queremos actualizar. Como la tabla virtual es recursiva entonces se le irán agregando filas hasta que la condición del JOIN deje de cumplirse. El último SELECT es el que devuelve todas las filas de la tabla virtual, y todas esas filas tienen una sola columna, llamada CUE_IDENTI.

Entonces, nuestro UPDATE recursivo sería el equivalente a este UPDATE no recursivo.

Listado 2.

UPDATE
   CUENTAS
SET
   CUE_TIMEST = CURRENT_TIMESTAMP
WHERE
   CUE_IDENTI IN (6, 7, 8, 9, 10)

¿Cuál es la diferencia? Que en el Listado 2. debemos conocer  todos los identificadores que deseamos actualizar, en cambio en el Listado 1., no. Allí solamente necesitamos conocer el identificador de la primera cuenta, nada más. Todas las cuentas que sean sus descendientes serán actualizadas, sean 4 como en este caso o sean 500 o sean 1000. La única limitación es que pueden ser como máximo 1024 porque el Firebird permite hasta 1024 recursiones.

El Listado 2. es más sencillo, pero requiere conocer los identificadores de todas las cuentas que queremos actualizar y si los usuarios están constantemente agregando cuentas tendremos que estar cambiando nuestro UPDATE a cada rato. Por el contrario con el Listado 1. lo único que debemos conocer es el identificador de la primera cuenta que deseamos actualizar y todas las cuentas que sean sus descendientes se actualizarán también.

Artículos relacionados:

Stored procedures recursivos

Entendiendo a las tablas autoreferenciadas

Usando CTE (Common Table Expression)

Otro ejemplo de CTE: ventas semanales

Usando varias CTE en una vista o en un stored procedure

FOR SELECT y tablas CTE

Usando recursividad con CTE

Ejemplo de recursión (1). Filas salteadas

Ejemplo de recursión (2). Numerar filas

Ejemplo de recursión (3). Fechas consecutivas

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

Pasos a seguir para actualizar la versión de Firebird

7 comentarios

En ocasiones ocurre que necesitamos cambiarnos a una versión más nueva del Firebird. Por ejemplo, estamos usando Firebird 1.5 y ahora queremos usar Firebird 2.5.2 ¿Qué debemos hacer en ese caso?

  1. Cerrar todas las conexiones a las bases de datos
  2. Backup con la versión vieja
  3. Verificación con la versión vieja
  4. Detener el Servidor del Firebird
  5. Iniciar la nueva versión del Servidor del Firebird
  6. Restaurar las bases de datos
  7. Actualizar las librerías cliente (el archivo FBCLIENT.DLL) en cada computadora cliente

Paso 1. Cerrar todas las conexiones a las bases de datos

Todos los usuarios deben desconectarse, nadie debe estar conectado. Para asegurarnos que después de todos haberse desconectado nadie más intente conectarse podríamos renombrar a la Base de Datos. Como los usuarios desconocen el nuevo nombre de la Base de Datos jamás conseguirán la conexión. Otra opción es usar el programa GFIX.EXE con la opción -force

Paso 2. Backup con la versión vieja

Esta siempre es una elemental medida de precaución porque si por cualquier motivo algo saliera mal entonces podríamos recuperar el 100% de nuestras bases de datos.

Paso 3. Verificación con la versión vieja

Siempre debemos verificar que los backups puedan ser restaurados exitosamente. Jamás debemos confiar en que se encuentran en buen estado, siempre debemos verificar que sea así antes de continuar. Si no verificamos nuestros backups podríamos encontrarnos con sorpresas muy desagradables cuando los necesitemos.

Entonces, se restaura el backup, y si no aparece algún mensaje de error durante la restauración eso significa que todo está ok

Paso 4. Detener el Servidor del Firebird

Una vez que hicimos un backup, verificamos que se encuentra en perfecto estado, y nos aseguramos de que nadie esté conectado a la Base de Datos, debemos detener el Servidor del Firebird. Si no lo hacemos, el Servidor podría continuar realizando tareas dentro de la Base de Datos sin que se las hayamos pedido (por ejemplo: un sweep, o una reindexación) y cuando nos conectemos con la nueva versión del Firebird habrá dos versiones accediendo a la misma Base de Datos y eso solamente puede ocasionar corrupción.

La probabilidad de que tal cosa ocurra no es alta pero ¿para qué dejar abierta la puerta a los problemas cuándo es tan fácil detener el Servidor del Firebird y asegurarnos de que no tendremos problemas?

Además, como seguramente sabes, puedes tener a dos o más versiones del Servidor del Firebird ejecutándose en la misma computadora. A veces es necesario que sea así. Pero si estás seguro de que ya no necesitarás a la versión vieja lo mejor es desinstalarla y así evitarás toda posibilidad de corrupción, porque si dos Servidores acceden a la misma Base de Datos en el mismo momento eso provoca corrupción.

Entonces ¿ya no necesitarás a la versión vieja del Firebird? desinstálala. ¿No estás seguro? desinstálala, porque siempre podrás volver a instalarla cuando la necesites

Paso 5. Iniciar la nueva versión del Servidor del Firebird

Ya el Servidor de la versión vieja está detenido, entonces podemos iniciar el Servidor de la versión nueva.

Paso 6. Restaurar las bases de datos

Las bases de datos originales no pueden (o no deben) ser usadas. Lo que debemos hacer es restaurarlas con la nueva versión del Firebird y así nos aseguraremos de que cuenten con todas las características de la nueva versión.

Recuerda: no uses la Base de Datos original, lo que debes hacer es restaurar su backup

Paso 7. Actualizar las librerías cliente (el archivo FBCLIENT.DLL) en cada computadora cliente

 Con el Paso 6. se terminó todo lo que le compete al Servidor, pero la tarea aún no está finalizada, porque todavía falta actualizar el archivo FBCLIENT.DLL en cada computadora que se conecta a las bases de datos.

 Si intentamos conectarnos a una Base de Datos administrada por un Servidor 2.5.2 con un Cliente 1.5 eso solamente nos causará problemas. Para conectarnos a un Servidor 2.5.2 debemos usar un Cliente 2.5.2

Conclusión:

Si queremos usar una versión más nueva del Firebird hay algunos pasos que debemos seguir, si no lo hacemos así entonces o no podremos conectarnos o perderemos datos, o corromperemos la Base de Datos. Y ninguna de esas opciones es buena.

Hacer el backup y la restauración no es algo instantáneo, puede tomar mucho tiempo, horas inclusive en bases de datos muy grandes, así que debemos realizarlos en los días o en los horarios en que menos usuarios suelen conectarse.

Artículo relacionado:

El índice del blog Firebird21

 

Ventas mensuales a cada cliente usando tablas agregadas

Deja un comentario

En este artículo hay otro ejemplo del uso de las tablas agregadas. Ahora, las usaremos para ver en columnas las ventas realizadas durante cada mes del año.

NOTA IMPORTANTE:

Los stored procedures CREAR_TABLA_PIVOT y ACTUALIZAR_TABLA_PIVOT han sido levemente modificados. Como seguramente sabes siempre el código fuente puede ser mejorado, y eso es justamente lo que sucedió con ellos. Las más nuevas versiones podrás descargar desde:

http://www.mediafire.com/view/ol58gyejul1t43a/CREAR_TABLA_PIVOT.txt

http://www.mediafire.com/view/1uebv8uerc5kwpe/ACTUALIZAR_TABLA_PIVOT.txt

Necesitarás de las nuevas versiones para que te funcionen los ejemplos que vienen a continuación.

Listado 1. La vista V_VENTAS

CREATE VIEW V_VENTAS(
   MVC_IDECLI,
   NOMBRE_MES,
   MVC_NOMCLI,
   MVC_TOTALX)
AS
   SELECT
      MVC_IDECLI,
      'MES_' ||
      LPAD(EXTRACT(MONTH FROM MVC_FECHAX), 2, '0') || '_' ||
      DECODE(
         EXTRACT(MONTH FROM MVC_FECHAX),
          1, 'ENE',
          2, 'FEB',
          3, 'MAR',
          4, 'ABR',
          5, 'MAY',
          6, 'JUN',
          7, 'JUL',
          8, 'AGO',
          9, 'SEP',
         10, 'OCT',
         11, 'NOV',
         12, 'DIC') AS NOMBRE_MES,
         CLI_NOMBRE AS MVC_NOMCLI,
         MVC_TOTALX
      FROM
         MOVIMCAB
      JOIN
         CLIENTES
            ON MVC_IDECLI = CLI_IDENTI;

AGREGADAS1

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

Ahora creamos la tabla agregada VENTAS1:

Listado 2. La tabla agregada VENTAS1

EXECUTE PROCEDURE
   CREAR_TABLA_PIVOT (
      'VENTAS1',
      'V_VENTAS',
      'MVC_IDECLI INTEGER',
      'MVC_NOMCLI VARCHAR(40)',
      'NOMBRE_MES',
      'NUMERIC(17, 4)')

AGREGADAS2

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

Y a continuación le agregamos datos:

Listado 3. Insertando filas a la tabla VENTAS1

EXECUTE PROCEDURE
   ACTUALIZAR_TABLA_PIVOT (
      'VENTAS1',
      'V_VENTAS',
      'MVC_IDECLI INTEGER',
      'MVC_NOMCLI VARCHAR(40)',
      'NOMBRE_MES',
      'SUM(MVC_TOTALX)')

AGREGADAS3

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

Y listo, ya está. Ya tenemos nuestra tabla agregada con un Cliente por cada fila y las ventas mensuales en las siguientes columnas. Este tipo de tablas puede ser muy útil para la toma de decisiones.

Fíjate que lo único que necesitamos hacer es escribir una vista que contenga los datos que utilizaremos, los stored procedures CREAR_TABLA_PIVOT y ACTUALIZAR_TABLA_PIVOT se encargan de todo lo demás.

Si no queremos ver los Identificadores de los clientes entonces podríamos crear la tabla de esta manera:

Listado 4. La tabla VENTAS1 sin los identificadores de los clientes

EXECUTE PROCEDURE
   CREAR_TABLA_PIVOT (
      'VENTAS1',
      'V_VENTAS',
      'MVC_NOMCLI VARCHAR(40)',
      '',
      'NOMBRE_MES',
      'NUMERIC(17, 4)')

La actualizaríamos así:

Listado 5. Insertando filas a la tabla VENTAS1 sin los identificadores de los clientes

EXECUTE PROCEDURE
   ACTUALIZAR_TABLA_PIVOT (
      'VENTAS1',
      'V_VENTAS',
      'MVC_NOMCLI VARCHAR(40)',
      '',
      'NOMBRE_MES',
      'SUM(MVC_TOTALX)')

Y obtendríamos este resultado:

AGREGADAS4

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

Que es bastante similar al anterior pero no idéntico ¿por qué no? porque en el anterior las filas aparecían ordenadas por Identificador del Cliente y en el actual aparecen ordenadas por Nombre del Cliente. Es decir que las filas siempre aparecen ordenadas por el contenido de la primera columna.

Artículos relacionados:

Creando y actualizando tablas agregadas de uso general

Otro ejemplo de uso de tablas agregadas

El índice del blog Firebird21

Actualización de saldos: cuando sí y cuando no

8 comentarios

Es muy común que los programadores quieran tener en una columna el saldo actualizado de ese ítem, pero … ¿es eso conveniente?

Supongamos que tenemos una tabla de PRODUCTOS con las columnas:

  • Identificador del producto
  • Código del producto
  • Nombre del producto
  • Cantidad inicial
  • Cantidad actual

Luego, cada vez que entra o sale un producto del stock se actualiza la columna “Cantidad actual” para así tener siempre a mano cual es la cantidad actual de dicho producto.

¿Es ésa una buena práctica?

No.

¿Por qué no?

Porque cada vez que una transacción actualiza una columna se bloquea la fila completa. La primera transacción que intente hacerlo no tendrá problemas pero las siguientes sí, porque la fila que quieren actualizar está bloqueada. Y en ese caso solamente tienen dos alternativas:

  1. Esperar que la transacción que tiene bloqueada a una fila la desbloquee
  2. Abandonar el intento de actualización con un mensaje de error

Y ninguna de esas alternativas es aceptable en un entorno donde hay mucha concurrencia (o sea, muchas computadoras queriendo actualizar el mismo ítem)

Ejemplo del problema que puede ocurrir:

Un supermercado tiene 25 cajas, es fin de año, época de muchas ventas. La caja 1 registra un producto, actualizando su cantidad en stock. Las cajas 7 y 18 quisieron actualizar también la cantidad en stock de ese producto y fueron rechazadas. La caja 1 liberó al producto, el cual ahora fue actualizado por la caja 7 pero la caja 18 continúa esperando. La caja 1 registra otro producto, y al hacerlo lo bloquea. Las cajas 12, 14, y 20 que querían también registrar ese producto no pueden hacerlo. La caja 3 bloqueó a otro producto, que la caja 5 también debe actualizar y por lo tanto no puede.

Puede ser un problema interminable porque cuando una caja libera a un producto otra caja lo bloquea.

Por lo tanto, querer tener actualizada la cantidad en stock de un producto que puede ser vendido desde muchas computadoras y al mismo tiempo, es un gran error.

A la gente no le gusta esperar, si tienen que estar esperando y esperando y esperando hasta que cada producto pueda ser registrado en la caja lo más probable es que se vayan y no vuelvan. Y si se van se pierden clientes, y si se pierden clientes se pierden ventas, y si se pierden ventas se pierde dinero. Y si pierden dinero, lo más probable es que los dueños de la empresa se deshagan rápidamente del programa inútil y del programador inútil, y contraten algo que realmente les sirva.

¿En qué casos sí se puede actualizar el saldo en línea?

Cuando la probabilidad de que el ítem sea accedido para actualización desde 2 ó más computadoras es cero o casi cero. Por ejemplo, en el momento en que se le vende a un cliente o se le cobra a un cliente sí es correcto actualizar su saldo. ¿Por qué? Porque es altamente improbable o imposible que al mismo cliente se le esté vendiendo o cobrando desde dos o más computadoras. Si el cliente está en la caja 5 pues está en la caja 5, no está también en la caja 12 y en la caja 18. Por lo tanto, es imposible que haya conflicto cuando se quiere actualizar su saldo.

Lo mismo sucedería con los proveedores. Es muy raro que un proveedor entregue varias facturas y esas facturas sean cargadas al mismo tiempo y en distintas computadoras; entonces actualizar su saldo cada vez que se carga una factura es correcto.

Algo similar sucede con los alumnos y las cobranzas de las cuotas. Es prácticamente imposible que al mismo alumno se le esté cobrando al mismo tiempo desde dos o más computadoras.

¿Cómo se obtiene el saldo actual si no se lo actualiza en línea?

Como vimos, en el caso de los productos de un supermercado sería un error querer tener actualizados los saldos de los productos en línea (o sea, en el mismo momento en que se venden). Pero los usuarios necesitan conocer ese saldo, ¿cómo lo solucionamos?

Hay dos alternativas:

  1. Si la velocidad con la cual se recuperan los datos de la consulta es alta, un simple SELECT será suficiente. A la cantidad inicial del producto (que tenemos guardada en la tabla PRODUCTOS) se le suman todas las entradas y se le restan todas las salidas, hallándose así la cantidad actual.
  2. Si realizar la consulta especificada en el punto 1. demora mucho, entonces se tiene una tabla de SALDOS que son actualizados periódicamente (una vez al día, una vez a la semana, una vez al mes, etc.) y luego a la cantidad que hay en esa tabla de SALDOS se le suman las entradas y se le restan las salidas. Por ejemplo, si la tabla de SALDOS se actualiza diariamente (por ejemplo: al final de la jornada laboral), para saber la cantidad actual de un producto se obtiene la cantidad que tenía ayer (ese dato está en la tabla de SALDOS) y se le suman todas las entradas y se le restan todas las salidas que ocurrieron el día de hoy.

Conclusión:

Cuando un ítem (por ejemplo: un producto) puede tener mucha concurrencia (o sea, que accedan a sus datos para modificarlos desde varias computadoras y al mismo tiempo) no se debe actualizar el saldo de ese ítem porque si se lo actualiza solamente acarreará problemas a los usuarios.

Cuando un ítem (por ejemplo: un proveedor) tiene baja concurrencia entonces sí es correcto actualizar su saldo.

La pregunta que debemos hacernos es: ¿es probable que al mismo tiempo se quiera actualizar el saldo de este ítem desde 2 ó más computadoras? Si la respuesta es afirmativa entonces no debemos actualizar el saldo.

Artículos relacionados:

Modos de bloqueo de las transacciones

Bloques mortales

El índice 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.

Usando UPDATE OR INSERT

5 comentarios

Supongamos que queremos hacer lo siguiente:

  • Si existe una fila de una tabla, entonces cambiar el contenido de alguna columna
  • Si no existe esa fila, agregarla a la tabla

Esta es una tarea muy común en los programas llamados de ABM (agregar, borrar, modificar) o sea los programas que los usuarios utilizan para introducir datos a las tablas.

La forma antigua de realizar esa tarea sería esta:

SET TERM ^ ;

CREATE PROCEDURE GRABAR_BANCO(
   tnIdenti BIGINT,
   tcNombre VARCHAR(40))
AS
BEGIN

   IF (EXISTS(SELECT * FROM BANCOS WHERE BAN_IDENTI = :tnIdenti)) THEN
      UPDATE
         BANCOS
      SET
         BAN_NOMBRE = :tcNombre
      WHERE
         BAN_IDENTI = :tnIdenti;
   ELSE
      INSERT INTO BANCOS
             (BAN_IDENTI, BAN_NOMBRE)
      VALUES (:tnIdenti , :tcNombre );

END^

SET TERM ; ^

También podríamos escribirlo así, quizás sea más claro para algunos:

SET TERM ^ ;

CREATE PROCEDURE GRABAR_BANCO(
   tnIdenti BIGINT,
   tcNombre VARCHAR(40))
AS
BEGIN

   UPDATE
      BANCOS
   SET
      BAN_NOMBRE = :tcNombre
   WHERE
      BAN_IDENTI = :tnIdenti;

   IF (ROW_COUNT = 0) THEN
      INSERT INTO BANCOS
             (BAN_IDENTI, BAN_NOMBRE)
      VALUES (:tnIdenti , :tcNombre );

END^

SET TERM ; ^

En este caso, intentamos actualizar la tabla y si la variable ROW_COUNT es igual a cero significa que no lo conseguimos porque no había fila para actualizar, así que procedemos a insertar la fila.

En esos dos stored procedures se utilizó la forma antigua, la forma tradicional, la que puede utilizarse en cualquier motor SQL. Sin embargo, el Firebird nos provee de una mucha mejor alternativa: el comando UPDATE OR INSERT, el cual primero trata de actualizar una fila y si no lo consigue, la inserta.

SET TERM ^ ;

CREATE PROCEDURE GRABAR_BANCO(
   tnIdenti BIGINT,
   tcNombre VARCHAR(40))
AS
BEGIN

   UPDATE OR INSERT INTO BANCOS
          (BAN_IDENTI, BAN_NOMBRE)
   VALUES (:tnIdenti , :tcNombre );

END^

SET TERM ; ^

Como puedes ver, se ha escrito mucho menos y el código es más legible (bueno, al menos para mí es más legible). En este ejemplo la columna BAN_IDENTI es la Primary Key de la tabla BANCOS y el comando UPDATE OR INSERT intenta actualizar una fila que tenga esa Primary Key. Si no lo consigue (porque ninguna fila tiene esa Primary Key) entonces le inserta una fila a la tabla de BANCOS. Claro, fácil, sencillo, se escribe menos y se entiende mejor.

Older Entries