Instalando Firebird silenciosamente

2 comentarios

Firebird puede ser instalado silenciosamente, es decir sin que se vean mensajes ni pantallas mientras se está instalando, eso puede ser muy útil cuando además del Firebird estamos instalando nuestra aplicación. También cuando queremos que se instale sin intervención del usuario.

Lo primero que debemos hacer, evidentemente, es descargar el ejecutable del Firebird, lo podemos encontrar en este enlace:

http://www.firebirdsql.org/en/firebird-2-5-2-upd1/

Instalación1

 

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

Luego, abrimos la ventana «Símbolo del sistema» con derechos de administrador (para ello buscamos el icono y hacemos clic con el botón derecho):

Instalación2

 

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

Y a continuación escribimos el nombre del ejecutable y sus opciones, por ejemplo:

Instalación3

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

De esta manera luego de esperar unos segundos habremos instalado al Firebird y durante la instalación ningún mensaje fue visible.

Las opciones que podemos utilizar para la instalación son las siguientes:

/? | /h | /HELP
/FORCE
/NOCPL
/NOGDS32
/COPYFBCLIENT
/COMPONENTS=»lista de componentes separados por comas»
/TASKS=»lista de tareas separadas por comas»
/MERGETASKS=»lista de tareas separadas por comas»

/CLEAN

/SP-
/SILENT | /VERYSILENT [/SUPPRESSMSGBOXES]
/LOG[=»Nombre_del_archivo»]
/NOCANCEL
/NORESTART
/RESTARTEXITCODE=código de salida
/LOADINF=»Nombre_del_archivo»
/SAVEINF=»Nombre_del_archivo»
/LANG=lenguaje
/DIR=»x:\Nombre_carpeta»
/GROUP=»Nombre_carpeta»
/NOICONS

Artículo relacionado:

El índice del blog Firebird21

 

Entendiendo la Integridad Referencial

2 comentarios

La «integridad referencial» es un concepto utilizado en las bases de datos y significa que la relación entre dos tablas siempre es consistente.

¿Qué significa la palabra «integridad»?

Que no pueden sobrar ni faltar datos, deben estar todos, ninguno más y ninguno menos.

¿Qué significa la palabra «referencia»?

Que conociendo algunos datos de una tabla se pueden conocer todos los datos de la otra tabla.

¿Cómo se establece la relación entre las dos tablas?

A través de una restricción Foreign Key.

En una restricción Foreign Key una de las tablas actúa como «padre» y la otra tabla actúa como «hija». La relación entre ambas tablas está dada por una columna (o más de una columna) cuyos tipos de datos son idénticos. Por ejemplo, se puede establecer entre una columna INTEGER de la tabla «padre» y una columna INTEGER de la tabla «hija», pero no se puede entre una columna INTEGER de la tabla «padre» y una columna VARCHAR de la tabla «hija».

  • SMALLINT con SMALLINT, ok
  • INTEGER con INTEGER, ok
  • BIGINT con BIGINT, ok
  • SMALLINT con VARCHAR, error
  • INTEGER con FLOAT, error
  • VARCHAR con DATE, error
  • etc.

¿Qué es una relación consistente?

Aquella en la cual cada fila de la tabla «hija» tiene una fila y solamente una fila correspondiente en la tabla «padre». Si una fila de la tabla «hija» no tiene una fila (y solamente una fila) correspondiente en la tabla «padre» entonces ya no existe la integridad referencial entre ambas tablas.

  • 1 fila de la tabla «hija» se corresponde con 0 filas de la tabla «padre» —> no hay integridad referencial
  • 1 fila de la tabla «hija» se corresponde con 1 fila de la tabla «padre» —> sí hay integridad referencial
  • 1 fila de la tabla «hija» se corresponde con 2 ó más filas de la tabla «padre» —> no hay integridad referencial

¿Qué debemos tener en cuenta para establecer una integridad referencial?

Que la relación entre la tabla «hija» y la tabla «padre» se haga mediante la Primary Key de la tabla «padre» o de una Unique Key de la tabla «padre».

¿Qué implica que entre dos tablas exista una integridad referencial?

  1. Que no puedes agregarle una fila a la tabla «hija» si no existe la fila correspondiente en la tabla «padre»
  2. Que no puedes cambiar la columna usada en la referencia en la tabla «padre» (a menos que hayas establecido «actualización en cascada»)
  3. Que no puedes borrar la fila usada en la referencia en la tabla «padre» (a menos que hayas establecido «borrado en cascada»)

¿Qué significan «actualización en cascada» y «borrado en cascada»?

  • «Actualización en cascada» significa que si cambias el valor de la columna en la tabla «padre» ese mismo cambio se efectuará automáticamente en todas las filas de la tabla «hija» correspondientes
  • «Borrado en cascada» significa que si borras una fila de la tabla «padre» todas las filas correspondientes de la tabla «hija» también serán borradas.

Ejemplo:

Tenemos una tabla llamada PAISES y otra tabla llamada PRODUCTOS. Queremos que la tabla PRODUCTOS referencie a la tabla PAISES, para poder así saber cual es el país del cual proceden nuestros productos.

INTEGRIDAD1

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

La Primary Key de esta tabla está compuesta por las columnas PAI_CODSUC y PAI_IDENTI

INTEGRIDAD2

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

Podemos establecer una restricción «Foreign Key» entre ambas tablas usando las dos columnas que tienen en común: Código de la Sucursal e Identificador del País:

ALTER TABLE PRODUCTOS ADD CONSTRAINT FK_PRODUCTOS3 FOREIGN KEY (PRD_CODSUC,PRD_IDEPAI) REFERENCES PAISES(PAI_CODSUC,PAI_IDENTI);

Como ambas tablas están relacionadas mediante una «Foreign Key», entonces:

  1. No podemos colocar en la columna PRD_IDEPAI un número que no exista en la columna PAI_IDENTI. O sea que el número que coloquemos en la columna PRD_IDEPAI debe existir en la columna PAI_IDENTI
  2. No podemos colocar NULL en la columna PRD_IDEPAI
  3. No podemos cambiar el número que se encuentra en la columna PAI_IDENTI si ese número existe en alguna columna PRD_IDEPAI
  4. No podemos borrar una fila de la tabla PAISES si el número de su columna PAI_IDENTI existe en la columna PRD_IDEPAI de alguna fila de la tabla PRODUCTOS

El punto 3. podemos hacerlo si establecimos «actualización en cascada», ejemplo:

ALTER TABLE PRODUCTOS ADD CONSTRAINT FK_PRODUCTOS3 FOREIGN KEY (PRD_CODSUC,PRD_IDEPAI) REFERENCES PAISES(PAI_CODSUC,PAI_IDENTI) ON UPDATE CASCADE;

El punto 4. podemos hacerlo si establecimos «borrado en cascada», ejemplo:

ALTER TABLE PRODUCTOS ADD CONSTRAINT FK_PRODUCTOS3 FOREIGN KEY (PRD_CODSUC,PRD_IDEPAI) REFERENCES PAISES(PAI_CODSUC,PAI_IDENTI) ON DELETE CASCADE;

Conclusión:

Siempre que sea posible debemos tener tablas con «integridad referencial» porque eso nos asegura de tener datos consistentes en las tablas «hijas».

Como no se puede guardar en una tabla «hija» un valor que no exista en su tabla «padre» eso nos da la seguridad de que todos los valores de la tabla «hija» existan en la tabla «padre» y evitamos así tener filas «huérfanas» (se llaman así a las que no tienen «padre»). Las filas huérfanas solamente pueden causar problemas y ningún beneficio.

Artículos relacionados:

Entendiendo a las Foreign Keys

El índice del blog Firebird21

Averiguando el tamaño en bytes de una tabla

Deja un comentario

¿Cuántos bytes ocupa en el disco duro una tabla?

Para responder a esta pregunta podemos hacer uso del programa GSTAT.EXE que viene incluido en la instalación del Firebird y que lo encontrarás en su carpeta \BIN

Hay que ejecutar el programa GSTAT con la opción -t y el nombre de la tabla que nos interesa.

Ejemplo:

Queremos averiguar cuantos bytes ocupa en el disco duro la tabla PROVEEDORES, para ello ejecutamos el programa GSTAT con la opción -t PROVEEDORES:

TAMANO1

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

Page size nos indica cual es el tamaño de cada página de la Base de Datos, en bytes. Todas las páginas tienen el mismo tamaño. En este ejemplo el tamaño de cada página es 4096 bytes como podemos ver en (1)

Data pages nos indica cuantas páginas ocupa la tabla, en este ejemplo la tabla se llama PROVEEDORES y ocupa 4 páginas, como podemos ver en (2)

Entonces, para saber cuantos bytes está ocupando en el disco la tabla PROVEEDORES simplemente multiplicamos el tamaño de cada página por la cantidad de páginas (4096 * 4) y obtenemos como  resultado 16384 bytes.

Artículo relacionado:

El índice del blog Firebird21

 

Un stored procedure para recrear todas las vistas

Deja un comentario

En ocasiones necesitamos recrear las vistas de nuestra Base de Datos; a veces ocurre que después de modificar la estructura de una tabla cuando queremos ejecutar una vista obtenemos el mensaje de error: «string truncation».

Como pueden ser varias las vistas afectadas por ese problema, lo más inteligente es tener un stored procedure que se encargue de recrearlas a todas:

CREATE PROCEDURE RECREAR_VISTAS
AS
   DECLARE VARIABLE lcNombreVista VARCHAR(   32);
   DECLARE VARIABLE lcCodigoVista VARCHAR(32765);
   DECLARE VARIABLE lcColumna     VARCHAR(   32);
   DECLARE VARIABLE lcComando     VARCHAR(32765);
   DECLARE VARIABLE lcFila        VARCHAR( 1024);
BEGIN

   -- Para cada vista de la Base de Datos
   FOR
      SELECT
         TRIM(R.RDB$RELATION_NAME),
         R.RDB$VIEW_SOURCE
      FROM
         RDB$RELATIONS R
      WHERE
         R.RDB$VIEW_SOURCE IS NOT NULL
      ORDER BY
         R.RDB$RELATION_NAME
      INTO
         :lcNombreVista,
         :lcCodigoVista
      DO BEGIN
         lcFila    = '';
         lcColumna = '';
         -- Para cada columna de esta vista
         FOR
            SELECT
               TRIM(F.RDB$FIELD_NAME)
            FROM
               RDB$RELATION_FIELDS F
            WHERE
               F.RDB$RELATION_NAME = :lcNombreVista
            ORDER BY
               F.RDB$FIELD_POSITION
            INTO
               :lcColumna
            DO
               IF (lcFila = '') THEN
                  lcFila = ' ' || :lcColumna;
               ELSE
                  lcFila = :lcFila || ', ' || ASCII_CHAR(13) || ASCII_CHAR(10) || ' ' || :lcColumna;
         -- Se modifica la vista
         lcComando = 'CREATE OR ALTER VIEW ' ||
                   :lcNombreVista || '(' ||
                   ASCII_CHAR(13) || ASCII_CHAR(10) ||
                   :lcFila ||
                   ') ' ||
                   ASCII_CHAR(13) || ASCII_CHAR(10) ||
                   'AS ' ||
                   :lcCodigoVista ;
         EXECUTE STATEMENT lcComando;
      END
END;

Este stored procedure se encargará de recrear a todas las vistas de la Base de Datos, asegurándonos por tanto que todas ellas se encuentran en perfectas condiciones.

¿Cómo funciona este stored procedure?

En primer lugar, obtiene el nombre de cada vista y el código fuente de ella.

En segundo lugar, obtiene el nombre de cada columna involucrada en esa vista.

En tercer lugar, guarda todos esos datos en una variable de tipo carácter.

En cuarto y último lugar, ejecuta el comando que recrea la vista.

Artículo relacionado:

El índice del blog Firebird21

 

Borrando filas cuando las condiciones están en otra tabla

1 comentario

A veces podemos necesitar borrar filas de una tabla, pero las filas que queremos borrar dependen de una o más condiciones de otra tabla.

Por ejemplo, escribimos esta consulta:

SELECT
   E.EMP_NOMBRE,
   E.EMP_APELLD,
   P.PRO_IDENTI,
   P.PRO_NOMBRE
FROM
   EMPLEADOS   E
JOIN
   PROFESIONES P
   ON E.EMP_IDEPRO = P.PRO_IDENTI
WHERE
   P.PRO_NOMBRE = 'Secretaria'

Y obtenemos este resultado, que nos muestra a todas las «Secretarias» que tenemos:

BORRAR1

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

Fíjate que la condición para mostrar las filas (la que se encuentra en el WHERE) depende de la tabla PROFESIONES, no de la tabla EMPLEADOS. Nuestra tabla principal es EMPLEADOS, pero la condición se encuentra en otra tabla, en la tabla de PROFESIONES.

Y ahora queremos borrar a todas las «Secretarias». Pero si escribimos algo así:

DELETE FROM
   EMPLEADOS   E
JOIN
   PROFESIONES P
   ON E.EMP_IDEPRO = P.PRO_IDENTI
WHERE
   P.PRO_NOMBRE = 'Secretaria'

no funcionará. ¿Por qué no? porque el comando DELETE no tiene una cláusula JOIN que podamos usar. Entonces, ¿cómo hacemos para borrar a todas las «Secretarias»?

Reemplazando la cláusula JOIN por la función EXISTS(), como vemos a continuación:

Solución 1

DELETE FROM
   EMPLEADOS E
WHERE
   EXISTS(SELECT
             PRO_NOMBRE
          FROM
             PROFESIONES P
          WHERE
             E.EMP_IDEPRO = P.PRO_IDENTI AND
             P.PRO_IDENTI = 1)

Solución 2

DELETE FROM
   EMPLEADOS E
WHERE
   EXISTS(SELECT
             PRO_NOMBRE
          FROM
             PROFESIONES P
          WHERE
             E.EMP_IDEPRO = P.PRO_IDENTI AND
             P.PRO_NOMBRE = 'Secretaria')

En la Solución 1 usamos el identificador con el cual se referencian las tablas de EMPLEADOS y de PROFESIONES, mientras que en la Solución 2 usamos el nombre de la Profesión.

Con ambas soluciones se obtiene exactamente el mismo resultado, así que ya dependerá de tí cual de ellas te resulta más conveniente. En general, lo recomendable es que cuando se quiere borrar una fila se use el identificador de esa fila (o sea su Primary Key) y no alguna otra columna, es más seguro así.

Lo que debes notar es que en la cláusula WHERE que se encuentra dentro de la función EXISTS() debes escribir la misma condición que escribiste en el JOIN y además la condición que escribiste en el WHERE de tu SELECT. Es solamente eso, como ves, se soluciona muy fácilmente.

Pero siempre verifica que el resultado obtenido es exactamente el buscado antes de ejecutar tu COMMIT, porque si escribes mal el WHERE podrías llegar a borrar todas las filas de la tabla, no solamente algunas.

Conclusión:

Ni el comando INSERT, ni el comando UPDATE, ni el comando DELETE cuentan con una cláusula JOIN pero siempre podemos simular un INNER JOIN si usamos la función EXISTS().

Lo que debemos recordar es verificar que el resultado obtenido sea exactamente el buscado antes de ejecutar el COMMIT, porque si escribimos una mala condición en el WHERE podríamos estar afectando a muchas más filas de las que deberían, con resultados catrastróficos.

Artículo relacionado:

El índice del blog Firebird21

Usando DISTINCT y EXISTS() eficientemente

1 comentario

En muchas consultas podemos obtener los mismos resultados si usamos la cláusula DISTINCT o la función EXISTS(). Pero obtener los mismos resultados no significa que ambas formas sean igual de rápidas.

Por ejemplo, podemos tener una tabla de PROFESIONES con estas filas:

DISTINCT_EXIST_1

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

Y una tabla de EMPLEADOS con estas filas:

DISTINCT_EXIST_2

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

Y lo que nos interesa saber es: ¿cuáles son las profesiones de nuestros empleados?

Consulta 1. Usando DISTINCT

SELECT
   DISTINCT
   P.PRO_IDENTI,
   P.PRO_NOMBRE
FROM
   PROFESIONES P
INNER JOIN
   EMPLEADOS E
      ON P.PRO_CODSUC = E.EMP_CODSUC AND
         P.PRO_IDENTI = E.EMP_IDEPRO
WHERE
   P.PRO_CODSUC >= 0

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

Consulta 2. Usando la función EXISTS()

SELECT
   P.PRO_IDENTI,
   P.PRO_NOMBRE
FROM
   PROFESIONES P
WHERE
   P.PRO_CODSUC >= 0 AND
   EXISTS (SELECT E.EMP_IDENTI FROM EMPLEADOS E WHERE E.EMP_CODSUC = P.PRO_CODSUC AND E.EMP_IDEPRO = P.PRO_IDENTI)

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

Conclusión:

Como puedes observar viendo la Captura 3 y la Captura 4, en ambos casos el resultado obtenido es el mismo, pero los tiempos y los consumos de memoria son distintos. En general, la función EXISTS() es más rápida que la cláusula DISTINCT … si hay un índice que pueda usar la función EXISTS() ¿por qué eso? porque si hay un índice, verifica que exista el dato buscado y listo, ya está; en cambio DISTINCT por cada fila que recorre debe verificar que ya no se encuentre en el resultado obtenido hasta ese momento, y eso lleva más tiempo.

Así que ¿en tu consulta has utilizado la cláusula DISTINCT? Cámbiala usando la función EXISTS() y verifica si obtienes más rápido el resultado.

Artículo relacionado:

El índice del blog Firebird21

Creando y usando tablas temporales

7 comentarios

En ocasiones necesitamos guardar datos en forma temporal, esos datos solamente nos son útiles durante un rato y luego ya son desechables. Para esas ocasiones es que podemos usar las tablas temporales.

¿Y por qué no usar una tabla normal y escribir un «DELETE FROM MiTabla» antes de insertarle datos? De esa manera obtendríamos los mismos resultados que usando una tabla temporal, ¿verdad?

Sí y no.

Si un solo usuario necesita de esos datos entonces sí, usar una tabla temporal o usar una tabla normal a la cual le borramos todas las filas antes de empezar el proceso sería exactamente lo mismo.

Pero la cuestión se complica cuando son dos o más los usuarios que necesitan usar esa tabla, por ejemplo si usamos tablas normales podría ocurrir algo como esto:

  • El usuario 1 borró todas las filas de la tabla
  • El usuario 1 le insertó algunas filas a la tabla
  • El usuario 1 hizo un COMMIT
  • El usuario 2 borró todas las filas de la tabla
  • El usuario 2 le insertó algunas filas a la tabla
  • El usuario 2 hizo un COMMIT
  • El usuario 1 quiere consultar las filas de la tabla …. y no encuentra las filas que él insertó, sino las filas que insertó el usuario 2

En cambio, si se usan tablas temporales algo como lo anterior jamás podría ocurrir porque cada usuario tiene su propia versión de la tabla temporal. Es decir que lo que hace el usuario 1 es totalmente independiente de lo que hace el usuario 2. El usuario 1 puede hacer lo que se le antoje en la tabla temporal que el usuario 2 jamás se enterará. Y viceversa.

A las tablas temporales en Firebird se las conoce como GTT (Global Temporary Table) y pueden ser de dos clases:

  • Confinadas a la transacción
  • Confinadas a la conexión

«Confinadas a la transacción» significa que la tabla temporal solamente puede tener filas mientras está siendo usada en una transacción. Cuando la transacción termina todas esas filas son automáticamente borradas definitivamente, sin importar como haya finalizado la transacción (con un COMMIT o con un ROLLBACK) porque en ambos casos todas las filas de la tabla temporal son borradas.

«Confinadas a la conexión» significa que la tabla temporal solamente puede tener filas mientras dure la conexión actual. Cuando la actual conexión con la Base de Datos termina, todas las filas de la tabla temporal son borradas definitivamente.

¿Cómo se crea una tabla temporal?

Escribiendo el comando «CREATE GLOBAL TEMPORARY TABLE MiTabla», definiendo las columnas y luego finalizando con la cláusula «ON COMMIT DELETE ROWS» (si queremos una tabla temporal confinada a la transacción) o con la cláusula «ON COMMIT PRESERVE ROWS» (si queremos una tabla temporal confinada a la conexión).

¿Las tablas temporales pueden tener Primary Key?

¿Las tablas temporales pueden tener Foreign Key?

Sí, pero limitadamente. Una tabla temporal no puede referenciar a una tabla normal. Tampoco una tabla temporal confinada a la conexión puede referenciar a una tabla temporal confinada a la transacción, por lo tanto las Foreign Keys posibles son:

  • De una tabla temporal confinada a la transacción a una tabla temporal confinada a la transacción
  • De una tabla temporal confinada a la conexión a una tabla temporal confinada a la conexión
  • De una tabla temporal confinada a la transacción a una tabla temporal confinada a la conexión

¿Las tablas temporales pueden tener Unique Key?

¿Las tablas temporales pueden tener índices?

 Sí

Ejemplo 1:

CREATE GLOBAL TEMPORARY TABLE TEMP (
   TEM_IDENTI D_IDENTIFICADOR NOT NULL,
   TEM_NOMBRE D_NOMBRE40)
ON COMMIT DELETE ROWS;

ALTER TABLE TEMP ADD CONSTRAINT PK_TEMP PRIMARY KEY (TEM_IDENTI);

Aquí, creamos una tabla temporal llamada TEMP la cual estará confinada a la transacción. O sea que cuando la transacción finalice con un COMMIT o con un ROLLBACK todas las filas de esta tabla desaparecerán. También le agregamos una Primary Key.

Ejemplo 2:

CREATE GLOBAL TEMPORARY TABLE TEMP2 (
   TEM_IDENTI D_IDENTIFICADOR NOT NULL,
   TEM_NOMBRE D_NOMBRE40)
ON COMMIT PRESERVE ROWS;

ALTER TABLE TEMP2 ADD CONSTRAINT PK_TEMP2 PRIMARY KEY (TEM_IDENTI);

Aquí, creamos una tabla temporal llamada TEMP2, la cual estará confinada a la conexión. O sea que cuando la conexión con la Base de Datos finalice todas las filas de la tabla TEMP2 serán eliminadas.

Verificando que las filas de las tablas temporales confinadas a la transacción son eliminadas

Para verificar que tanto un COMMIT como un ROLLBACK eliminan a todas las filas de la tabla temporal confinada a la transacción escribimos lo siguiente:

GTT1

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

Como puedes ver, el primer SELECT mostró todas las filas insertadas pero el segundo SELECT no, ¿por qué? porque se escribió un COMMIT antes de él y con eso se finalizó la transacción. O sea que el segundo SELECT ya está en otra transacción.

GTT2

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

En este caso se escribió un ROLLBACK antes del segundo SELECT y el resultado fue el mismo que obtuvimos al escribir el COMMIT, o sea: ninguna fila mostrada. Lo cual significa que tanto si la transacción finaliza con un COMMIT o con un ROLLBACK todas las filas de la tabla temporal son eliminadas. El segundo SELECT ya está en otra transacción porque la transacción anterior finalizó con el ROLLBACK.

¿En qué casos es recomendable usar tablas temporales?

Cuando te facilitan la vida. El caso típico es cuando debes realizar una consulta que involucra a varias tablas normales pero esa consulta es demasiado complicada, tiene un montón de condiciones en el WHERE o en el HAVING, y muchos JOINs o UNIONs y te cuesta llegar al resultado deseado porque tu SELECT nunca te muestra lo que te debería mostrar, por más que lo intentas y lo intentas, nunca obtienes lo que deberías obtener y ya te da dolor de cabeza. Entonces, en lugar de estar lidiando con un SELECT inmenso, que te marea de solo mirarlo, es mucho más conveniente filtrar el contenido de las tablas involucradas, colocarlos en algunas tablas temporales y luego con unos pocos JOINs obtienes lo que buscabas.

Al usar tablas temporales seguramente escribirás más, pero todo lo que escribas será fácilmente entendible y entonces obtener las filas deseadas será muy rápido.

Entonces ¿tu SELECT involucra a varias tablas normales, las condiciones del WHERE o del HAVING son muchas y no obtienes lo que deseas? Empieza a pensar en usar tablas temporales.

Artículo relacionado:

El índice del blog Firebird21

Usando ISQL.EXE para extraer los metadatos

1 comentario

Como seguramente sabes, en cada instalación de Firebird viene incluido un programa llamado ISQL.EXE (Interactive SQL) con el cual puedes realizar todas las operaciones posibles en una Base de Datos (crearla, conectarte a ella, agregarle dominios, tablas, índices triggers, stored procedures, insertar filas, modificar filas, borrar filas, etc., etc. etc.)

También podemos usar ese programa para extraer los metadatos y guardarlos en un archivo de texto plano ¿para qué necesitaríamos hacer algo así? por muchas razones, por ejemplo:

  • Verificar que todos los metadatos son los correctos
  • Verificar que no esté sobrando algún dominio
  • Cambiarle el nombre a una tabla

No es necesario usar ISQL.EXE para estas tareas, las mismas puedes también realizarlas con cualquier administrador gráfico como el EMS SQL Manager, el IBExpert, el Flame Robin, etc., pero la ventaja de hacerlas con ISQL.EXE es que este programa está siempre disponible, siempre lo tenemos a nuestra disposición, en cambio podría darse el caso que no contemos con los otros programas.

Enviar los metadatos a un archivo de texto plano tiene la gran ventaja de que muy rápidamente podemos encontrar la información que necesitamos, por ejemplo:

  • ¿Hay algún índice descendente?
  • ¿Hay alguna tabla sin Primary Key?
  • ¿Los nombres de todas las tablas son los correctos?
  • ¿Todas las tablas hijas tienen Foreign Keys a sus tablas padres?
  • ¿Hay algún dominio que no se esté usando?
  • ¿Todas las tablas que deberían tener columnas calculadas, tienen columnas calculadas?
  • Y un largo etcétera

¿Cómo enviamos los metadatos a un archivo de texto usando ISQL.EXE?

  1. Abriendo la ventanita «Símbolo del sistema» del Windows
  2. Ubicándonos en la carpeta donde se encuentra el programa ISQL.EXE
  3. Escribiendo: ISQL -extract MiBaseDatos > MiArchivoTexto

Donde «MiBaseDatos» puede ser la ruta y el nombre completos de la Base de Datos o simplemente un alias que hayamos especificado en el archivo ALIASES.CONF

ISQL1

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

En este ejemplo, el alias de la Base de Datos es ERP2000 (se lo definió en el archivo ALIASES.CONF) y el nombre del archivo de texto es ERP2000.SQL (el nombre y la extensión pueden ser cualesquiera, en el caso de la extensión la que más se usa es .SQL) y el símbolo «mayor que» es el utilizado por el DOS para redirigir la salida a un archivo.

Luego de unos segundos, cuando el programa ISQL.EXE finalice su tarea tendremos un archivo de texto llamado ERP2000.SQL conteniendo los metadatos de ERP2000.FDB

Podemos ver el contenido de ese archivo de texto con cualquier programa que permita leer archivos de texto, por ejemplo con el Bloc de Notas del Windows.

ISQL2

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

En la Captura 2 puedes ver los primeros metadatos.

Ahora, ya es muy fácil revisar el archivo de texto y encontrar cualquier inconsistencia que tenga la Base de Datos.

Artículo relacionado:

El índice del blog Firebird21

 

Consultas a bases de datos externas

9 comentarios

A veces en nuestra Base de Datos actual no están todos los datos que necesitamos pues algunos se encuentran en otras bases de datos. ¿Podemos consultar esas otras bases de datos?

La respuesta es sí y la forma de hacerlo es mediante el comando EXECUTE STATEMENT. Sin embargo hay dos puntos importantes que debes recordar:

  1. El Firebird no valida que el EXECUTE STATEMENT sea correcto antes de ejecutarlo, por lo tanto eres tú quien debe asegurarse de ello
  2. El EXECUTE STATEMENT es lento (a veces puede ser demasiado lento)

Los dos puntos anteriores implican que debes sopesar bien si vale la pena usar el EXECUTE STATEMENT o si mejor sería pensar en otra alternativa.

Ejemplo:

En una Base de Datos llamada ERP2000.FDB tenemos una tabla llamada CARGOS que tiene estas filas:

EXTERNAS1

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

La columna CAR_IDENTI es el identificador del cargo, se usa internamente para referenciar a otras tablas con esta tabla. La columna CAR_CODIGO es la que se le muestra a los usuarios, ellos nunca ven la columna CAR_IDENTI ¿por qué? porque no necesitan verla, es para uso interno.

En otra Base de Datos, llamada BLOG_DB.FDB queremos ver las filas de la tabla CARGOS de ERP2000.FDB, para eso en BLOG_DB.FDB escribimos el siguiente stored procedure seleccionable:

SET TERM ^ ;

CREATE PROCEDURE OBTENER_CARGOS
RETURNS(
   ftnCodSuc SMALLINT,
   ftnIdenti INTEGER,
   ftcCodigo CHAR(4),
   ftcNombre VARCHAR(25))
AS
   DECLARE VARIABLE lcComando VARCHAR(256);
BEGIN

   lcComando = 'SELECT CAR_CODSUC, CAR_IDENTI, CAR_CODIGO, CAR_NOMBRE FROM CARGOS' ;

   FOR EXECUTE STATEMENT
      lcComando
   ON EXTERNAL
      'E:\SQL\SQL_CONTA\DATABASES\ERP2000.FDB'
   AS
      USER     'SYSDBA'
      PASSWORD 'masterkey'
   INTO
      :ftnCodSuc,
      :ftnIdenti,
      :ftcCodigo,
      :ftcNombre
   DO BEGIN
      SUSPEND;
   END

END^

SET TERM ; ^

Y después de escribir este comando:

SELECT * FROM OBTENER_CARGOS

este será el resultado que obtendremos:

EXTERNAS2

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

donde, como puedes ver, están todas las filas de la tabla CARGOS aunque los nombres de las columnas difieren porque los nombres de ellas son los que elegimos como parámetros de salida en nuestro stored procedure.

Conclusión:

Es perfectamente posible consultar bases de datos externas con Firebird pero como esa consulta se realiza con el comando EXECUTE STATEMENT a veces obtener los resultados puede demorar mucho tiempo por lo tanto debes verificar que la velocidad de respuesta esté dentro de los límites aceptables. En general si la tabla externa no tiene demasiadas filas no habría problemas. «Demasiadas filas» depende de tu hardware y de tu software, así que debes verificar.

Artículos relacionados:

Insertar, modificar o borrar filas en una Base de Datos externa

Importar datos desde otra Base de Datos

El índice del blog Firebird21

Averiguando el tamaño de la Base de Datos

Deja un comentario

Si necesitas conocer el tamaño de tu Base de Datos en bytes, puedes escribir la siguiente consulta:

SELECT
   MON$PAGES * MON$PAGE_SIZE AS TAMANO_EN_BYTES
FROM
   MON$DATABASE

Lo que hace esa consulta es multiplicar la cantidad total de páginas que tiene la Base de Datos por el tamaño de cada página, hallando así el tamaño de la Base de Datos.

Artículo relacionado:

El índice del blog Firebird21

Older Entries