100% encontró este documento útil (1 voto)
843 vistas55 páginas

Guía Completa de Firebird SQL

Este documento proporciona una introducción a Firebird, incluyendo su arquitectura, características principales como transacciones y concurrencia, y ejemplos básicos de sentencias SQL para la creación de tablas, selección de datos, y modificación de la estructura de base de datos. También cubre temas como instalación, herramientas, integridad referencial, y el lenguaje de definición de datos para crear y modificar objetos de base de datos.

Cargado por

garay_77
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (1 voto)
843 vistas55 páginas

Guía Completa de Firebird SQL

Este documento proporciona una introducción a Firebird, incluyendo su arquitectura, características principales como transacciones y concurrencia, y ejemplos básicos de sentencias SQL para la creación de tablas, selección de datos, y modificación de la estructura de base de datos. También cubre temas como instalación, herramientas, integridad referencial, y el lenguaje de definición de datos para crear y modificar objetos de base de datos.

Cargado por

garay_77
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Firebird

1 de 76

[Link]

CREATE TABLE prueba (


clave integer not null primary key,
hora time,
fecha date,
todo timestamp)

29/06/2012 02:33 a.m.

Firebird

2 de 76

[Link]

Firebird................................................................................................................................................... 1
Introduccin............................................................................................................................................ 5
Descripcin y caractersticas generales.................................................................................................... 5
Arquitectura....................................................................................................................................... 7
Servidor........................................................................................................................................ 7
Cliente.......................................................................................................................................... 7
Bloqueos, versiones y generaciones................................................................................................ 7
Operaciones con mltiples tablas.............................................................................................................. 9
Transacciones.................................................................................................................................... 9
Concurrencia 1: niveles de aislamiento de transacciones................................................................. 11
Concurrencia 2: modo de bloqueo de una transaccin..................................................................... 12
Bloqueos pesimistas..................................................................................................................... 14
Mantener el contexto................................................................................................................... 15
Integridad referencial........................................................................................................................ 15
Instalacin y puesta en marcha............................................................................................................... 17
Descarga desde Internet................................................................................................................... 17
Probar la instalacin.......................................................................................................................... 17
ISQL.......................................................................................................................................... 18
Herramientas................................................................................................................................... 19
IBServer..................................................................................................................................... 19
IBGuardian.................................................................................................................................. 19
ISQL.......................................................................................................................................... 19
Gbak........................................................................................................................................... 19
IBConsole................................................................................................................................... 19
Ejecutar sentencias SQL en IBConsole.................................................................................... 21
IBOConsole................................................................................................................................ 22
IB_SQL...................................................................................................................................... 23
SQL..................................................................................................................................................... 24
El lenguaje de consulta...................................................................................................................... 24
SQLSQL son las iniciales de......................................................................................................... 24
Cursores vs conjuntos....................................................................................................................... 24
Seleccin de registros: SELECT........................................................................................................ 25
Orden en la sala........................................................................................................................... 29
Filtrados y bsquedas................................................................................................................... 30
Fechas/Horas en SQL.................................................................................................................. 32

29/06/2012 02:33 a.m.

Firebird

3 de 76

[Link]

Criterios de seleccin................................................................................................................... 34
Funciones.................................................................................................................................... 38
Funciones de agregacin.............................................................................................................. 38
Subconsultas................................................................................................................................ 41
Comparacin con el resultado de una subconsulta.......................................................................... 43
Uniones....................................................................................................................................... 45
Consulta de varias tablas relacionadas........................................................................................... 45
Creacin, modificacin y borrado de objetos............................................................................................ 52
Lenguaje de Definicin de Datos (DDL)............................................................................................ 52
Bases de Datos........................................................................................................................... 52
Creacin de una base de datos................................................................................................. 52
El tamao no importa (perdn, Godzilla!)................................................................................... 53
Pginas.................................................................................................................................. 53
El juego de caracteres............................................................................................................. 54
Modificacin de una base de datos........................................................................................... 57
Borrado de una base de datos.................................................................................................. 58
Tablas......................................................................................................................................... 58
Creacin de una tabla.............................................................................................................. 58
Nombres de objetos................................................................................................................. 59
Tipos de datos soportados por Firebird...................................................................................... 59
Condiciones para los campos................................................................................................... 60
Campos calculados.................................................................................................................. 61
Restricciones.......................................................................................................................... 62
Modificacin de la estructura de una tabla................................................................................ 63
Borrado de una tabla completa................................................................................................. 65
Dominios..................................................................................................................................... 65
Creacin de dominios.............................................................................................................. 65
Modificacin de dominios......................................................................................................... 66
Borrado de dominios................................................................................................................ 66
Indices........................................................................................................................................ 66
Crear un ndice....................................................................................................................... 66
Modificar un ndice.................................................................................................................. 66
Borrar un ndice...................................................................................................................... 67
Restricciones.................................................................................................................................... 67
PK.............................................................................................................................................. 67
UQ............................................................................................................................................. 67
FK.............................................................................................................................................. 67
Check......................................................................................................................................... 67

29/06/2012 02:33 a.m.

Firebird

4 de 76

[Link]

Not Null...................................................................................................................................... 67
Generadores..................................................................................................................................... 67
Crear un generador...................................................................................................................... 68
Modificar un generador................................................................................................................ 68
Borrar un generador..................................................................................................................... 69
Excepciones..................................................................................................................................... 69
Definir excepciones..................................................................................................................... 69
Modificar excepciones................................................................................................................. 69
Borrar excepciones...................................................................................................................... 69
Programacin del servidor...................................................................................................................... 70
Scripts............................................................................................................................................. 70
Procedimientos almacenados............................................................................................................. 71
Procedimientos de accin............................................................................................................. 71
Triggers................................................................................................................................................ 72
Funciones del usuario (UDF).................................................................................................................. 73
Libreras estndar de funciones externas............................................................................................ 73
Crear funciones externas en Delphi................................................................................................... 73
Acceso desde Delphi............................................................................................................................. 74
BDE................................................................................................................................................ 74
IBX................................................................................................................................................. 74
DBX................................................................................................................................................ 74
ADO............................................................................................................................................... 74
IBO................................................................................................................................................. 74
UIB................................................................................................................................................. 74
Optimizacin......................................................................................................................................... 75
Plan de ejecucin.............................................................................................................................. 75
Creacin de ndices........................................................................................................................... 75
Selectividad...................................................................................................................................... 75
Restricciones declarativas vs. activas................................................................................................. 75
Restriccin de la cantidad de registros a traer al cliente....................................................................... 75
Futuro................................................................................................................................................... 75

29/06/2012 02:33 a.m.

Firebird

5 de 76

[Link]

El mundo de las Bases de Datos es ancho y ajeno, parafraseando a un escritor muy conocido. Existen muchos sistemas
de stos, con caractersticas que los distinguen unos de otros. No obstante, todos comparten el mismo ncleo de
funcionalidad, su objetivo bsico: sirven para almacenar y procesar datos, a veces cantidades realmente grandes.
Las diferencias vienen despus. Cmo se almacenan los datos, qu tipos de datos pueden contener, qu tan avanzado es
el lenguaje que permite consultar esos datos, caractersticas avanzadas para optimizar el proceso de grandes cantidades
de datos, por nombrar unas pocas. Aqu veremos solamente uno de estos sistemas en realidad dos, ya que son
prcticamente iguales- aunque me referir eventualmente a otros sistemas para hacer algunas comparaciones que nos
permitan situarnos mejor en el tema.
El sistema principal que es objetivo del presente se denomina Firebird, literalmente Pjaro de fuego, el Fnix que
renace de sus cenizas. No tengo confirmacin oficial, pero creo que el nombre se eligi por las mltiples vidas que
ha tenido el proyecto Interbase, que culminaron en Firebird. Las caractersticas de este gestor de datos son
prcticamente iguales hasta la versin 1.0- a las de Interbase de Borland en su versin 6.0. Y es que Firebird fue
creado a partir de los fuentes de Interbase 6.0, liberados por Borland bajo licencia IPL. Un conjunto de excelentes y
voluntariosos programadores se impuso la tarea de llevar adelante el gestor de datos sin costo, agregando y mejorando
caractersticas. En estos momentos (Febrero 2003) ya est disponible la beta 2 de la versin 1.5 de Firebird, que ya se
aparta un poco de Interbase proveyendo caractersticas diferenciales tanto en el lenguaje de consulta como en los
procesos internos.
Por su lado, Borland sigue avanzando tambin con Interbase pero ya no en forma gratuita. Se han liberado ya dos
versiones ms de Interbase, 6.5 y 7. Las mejoras y nuevas caractersticas de estas versiones no estn disponibles en
Firebird, o tienen otros nombres y sintaxis. Borland ya tom partido en cuanto a Firebird: no se va a hacer ningn
esfuerzo por mantener la compatibilidad, no slo de Interbase sino tampoco en los componentes de acceso de sus
herramientas de desarrollo. As, por ejemplo, el controlador DBExpress de Interbase soporta las caractersticas nuevas
de Interbase 7 pero no las de Firebird 1.5. Cuando hablemos de las formas de acceder por programa al servidor nos
ocuparemos de estos problemas y las soluciones que estn apareciendo.

Firebird es un Gestor de Bases de Datos Relacionales. Es decir que trabaja con el esquema relacional surgido en los
laboratorios de IBM, de la mano de E. F. Codd y Chris Date. Este esquema ha sido implementado con xito en forma
comercial, y de hecho la mayora de las aplicaciones de Bases de Datos se utilizan gestores que trabajan con este
[1]
modelo .
Firebird es pequea una instalacin completa ocupa alrededor de 10 Mb incluyendo libreras, ejemplos de
programacin y BD de muestra-, fcil de instalar y ejecutar, y an as muy poderosa. Puede trabajar muy bien con
cantidades de datos que van desde unos pocos hasta varios millones de registros por tabla. Generalmente no es
necesario tomar medidas especiales para optimizar el rendimiento del servidor, aunque tenemos la posibilidad de tocar
algunas variables para sacar ms provecho a situaciones particulares.
Se puede ejecutar en una amplia variedad de sistemas operativos: Windows en todas sus encarnaciones, Linux, Solaris,
[2]
MacOS y otros .
Por su tamao, rendimiento y poca necesidad de mantenimiento es un gestor ideal para aplicaciones pequeas y
medianas, que se puede llevar sin problemas a trabajar en situaciones ms exigentes y con mayor carga de trabajo y

29/06/2012 02:33 a.m.

Firebird

6 de 76

[Link]

datos.
Fsicamente, Firebird trabaja con uno o varios archivos adonde almacena todos los datos y estructuras: no ms
proliferacin de archivos como tenamos con Paradox o Dbase. Los archivos de Firebird 1.0 al igual que los de
Interbase 6.0- pueden tener hasta 2 Gb de tamao cada uno.
Firebird posee la mayora de las caractersticas avanzadas de los gestores modernos:

Transacciones

Posibilidad de definir ndices ascendentes o descendentes, con restriccin de unicidad

Posibilidad de definir restricciones a los datos en la declaracin de las tablas, como ser
o

Integridad referencial

Unicidad

Controles de validacin (Check)

Columnas computadas, slo de lectura

Posibilidad de programacin del servidor mediante disparadores triggers- y procedimientos almacenados


stored procedures.

Posibilidad de definir procedimientos almacenados que devuelvan tablas virtuales

Posibilidad de definicin de vistas

Generadores de nmeros secuenciales, independientes de las transacciones

Excepciones

Eventos

Funciones definidas por el usuario

Dominios

Un lenguaje SQL amplio y potente, que contempla funciones avanzadas como ser
o

Subconsultas

Uniones

Funciones de agregacin

Ordenamiento por columnas calculadas, etc

Vectores multidimensionales (matrices)

En el apndice <<<??>>> se puede ver un resumen de las caractersticas y lmites tcnicos de Firebird.

Arquitectura
Firebird se compone de dos partes: el servidor propiamente dicho, y el cliente que se comunica con l.

Servidor

29/06/2012 02:33 a.m.

Firebird

7 de 76

[Link]

El servidor es la parte que hace el trabajo: almacena los datos, los procesa, ejecuta los procedimientos almacenados y
aplica las validaciones. Debe existir uno por lo menos en la red.

Cliente
El cliente es la parte que se encarga de la comunicacin entre las aplicaciones y el servidor. Maneja los protocolos,
enva y recibe datos, enva comandos, etc. Es una capa mnima una librera de enlace dinmico, algunos archivos
auxiliares y entradas en el registro de servicios del sistema- pero necesaria para la comunicacin con el servidor. Debe
instalarse en todos los equipos que vayan a acceder al servidor, incluido el equipo adonde resida fsicamente el mismo
servidor si se va a usar como terminal.

Bloqueos, versiones y generaciones


La principal caracterstica que distingue a Firebird/Interbase del resto de los gestores comerciales conocidos como
Oracle, SQLServer o MySQL es su arquitectura generacional.
La mayora de los gestores de datos relacionales implementan un mecanismo de transacciones, y Firebird no es la
excepcin; la diferencia est en cmo se implementa el mecanismo. Generalmente se utilizan bloqueos de diferentes
niveles registro, pgina, tabla- para impedir que otras transacciones modifiquen datos que se estn procesando. Esto
tiene la desventaja de que esas transacciones quedarn imposibilitadas de trabajar con los datos bloqueados hasta que la
transaccin que impuso el bloqueo termine.
Pensemos en el siguiente ejemplo: una empresa tiene que consolidar los datos de los inventarios de sus sucursales, para
lo cual tiene que leer los valores de cada sucursal y acumularlos. La aplicacin que har la consolidacin comienza una
transaccin y va leyendo y sumando los datos de cada sucursal; no modifica nada, por lo que no seran necesarios los
bloqueos termina de sumar todo, almacena o muestra el resultado y termina la transaccin. Todos contentos.
Ahora pensemos qu pasara si en el medio del clculo una sucursal transfiere productos a otra, o simplemente los
vende.
Claro que la operacin debe quedar registrada en la base de datos, por lo que cambian los datos que se estn
sumando si no tomamos medidas, podemos llegar a sumar varias veces los mismos productos, o a dejar alguno
afuera.
Estas situaciones se controlan mediante los distintos niveles de aislamiento de las transacciones, que indican lo que una
transaccin ver de los cambios que produce otra transaccin que se activa al mismo tiempo. Para que los datos de la
transaccin que acumula sean fidedignos, se debe usar el nivel de aislamiento ms alto posible: esta transaccin no
debera ver los cambios hechos por las dems en todo el tiempo que dure. Este nivel se denomina generalmente de
lecturas repetibles.
Para lograr este nivel de aislamiento sera necesario bloquear los cambios a todos los registros a considerar, o hacer
una copia (una nueva generacin de datos) de los registros usados para la acumulacin, que entonces podran ser ledos
cuantas veces fuera necesario. La mayora de los gestores de bases de datos utilizan el primer mecanismo; Firebird usa
el segundo.

En breve: cada vez que se hace una modificacin a un registro, se crea una nueva versin o generacin del mismo
marcndola con un nmero que identifica a la transaccin que realiz el cambio. Con la ayuda de otra estructura de la
que hablaremos enseguida, este mecanismo permite a Firebird lograr el nivel de lecturas repetibles sin usar bloqueos,
as como evitar el uso de archivos de registro de operaciones (log).

[3]
Las transacciones existentes en un determinado momento en la base de datos pueden estar en uno de tres estados :

Activa

Aceptada (Committed)

Cancelada (Rolled back)

29/06/2012 02:33 a.m.

Firebird

8 de 76

[Link]

El estado de todas las transacciones existentes en la BD es mantenido en las Pginas de Inventario de Transacciones o
TIP (Transaction Inventory Pages). Es una lista de todas las transacciones que tienen datos en la base en cada
momento, acompaadas de su estado.
Cuando comienza una transaccin, se le asigna un nmero nico que la identifica (llamado UTN, Unique Transaction
Number) y se le entrega una lista de todas las transacciones que tienen datos en la base y sus estados a ese momento:
una copia de la TIP.
Los nmeros identificadores de las transacciones (UTNs) son enteros crecientes en el tiempo; es decir, si una
transaccin comienza despus de otra es seguro que recibir un UTN ms grande que la primera. La consecuencia
inversa ser muy usada en el mecanismo de versiones: si hay dos versiones de un mismo registro, la que tenga la UTN
ms grande ser posterior a la otra.
Cuando una transaccin tiene que actualizar un registro, busca en su TIP si haba otras transacciones activas al
momento de comenzar. Si no hay ninguna otra, entonces actualiza el registro sin ms. Pero si encuentra al menos una
transaccin activa en la TIP, no modifica el registro original: crea una nueva versin almacenando las diferencias (para
ahorrar espacio) y su propio nmero de transaccin, el UTN.
Ahora bien, si una transaccin quiere leer un registro, compara su propio identificador con el de la ltima versin del
registro. Si el UTN de la ltima versin es mayor al de la transaccin en cuestin, se toma la versin anterior del
registro. As se recorre la cadena de versiones hasta encontrar una cuyo UTN sea menor que el de la transaccin, y que
adems est marcada como Aceptada en el inventario (TIP). Cualquier otra versin es pasada por alto.

Ejemplo. Supongamos que tenemos la siguiente secuencia temporal:

1. La transaccin 100 modifica un registro. Se crea una versin con UTN=100.


2. Se acepta la transaccin 100 (estado: committed)
3. Comienza la transaccin 103, que modifica el mismo registro. Se crea una nueva versin con UTN=103.
4. Se cancela la transaccin 103 (estado: rolled back)
5. Comienza la transaccin 110, que modifica el registro. Se crea una nueva versin con UTN=110. La transaccin
no termina todava (estado: active)
6. Comienza la transaccin 112.
7. Comienza la transaccin 115, que modifica el registro. Se crea una nueva versin con UTN=115.
8. Se acepta la transaccin 115 (estado: commited)
9. La transaccin 112 lee el registro en cuestin. Cul es la versin que recupera?
La versin 115 es posterior a su propio UTN, por lo que no se considera. Busca el anterior.
La versin 110 corresponde a una transaccin que no ha terminado (estado = active) por lo que tambin se
ignora.
La versin 103 corresponde a una transaccin cancelada, por lo que tambin se ignora.
Finalmente, la versin 100 es correcta y es la que se recupera.

Con este mecanismo se obtienen dos beneficios directos:

Se trabaja en un nivel de aislamiento de lecturas repetibles sin bloquear las actualizaciones concurrentes a la
lectura

No se necesita llevar un registro de las operaciones para recuperar la base de datos de fallos; toda la
informacin est incluida en las versiones y la TIP. Lo nico que necesita hacer el servidor para recuperar una
base de datos despus de un fallo de alimentacin por ejemplo, es recorrer la TIP y marcar como canceladas a
todas las transacciones que figuran como activas. De esta manera, los cambios que se haban producido son

29/06/2012 02:33 a.m.

Firebird

9 de 76

[Link]

ignorados en subsecuentes operaciones.

Por supuesto que tambin hay alguna contra: la base de datos va acumulando basura en la forma de versiones que no
son utilizables. Esto obliga a ejecutar una accin de limpieza a intervalos, proceso que se denomina sweep. Este
proceso elimina las versiones anteriores de los registros, dejando solamente la ltima valida, pero puede impactar
negativamente en la performance del servidor. Por defecto se ejecuta automticamente cada 20.000 transacciones. Se
puede configurar esta cantidad en los parmetros del servidor, y tambin se puede ejecutar manualmente la limpieza.

[ERC1]
[ERC2]

En el modelo relacional tenemos que lidiar con operaciones que involucran varias tablas. Por ejemplo, el tpico caso de
un pedido o una factura: tendremos por lo menos dos tablas, una para los datos que identifican al pedido (fecha, cliente,
nro, etc) y la otra con los datos de cada item que compone el pedido (cantidad, codigo, precio unitario, etc). Cuando se
ingresa una factura, tambin generalmente modificaremos datos en otras tablas: stock o inventario, cuenta corriente del
cliente, etc. Sera muy problemtico si por cualquier causa como un corte de conexin- se interrumpe el proceso de
actualizacin de algunas tablas despus de terminar con otras: pueden quedar registros hurfanos, por ejemplo items
que no tienen factura, o datos desactualizados como el total de la cuenta corriente del cliente.
Hay varias tcnicas para combatir estos problemas, un par de las cuales veremos ahora: transacciones y restricciones de
integridad referencial.

Transacciones
Una transaccin es un conjunto de operaciones que se aceptan (Commit) o rechazan (Rollback) como una sola. Son
como parntesis que encierran las operaciones que se deben realizar o cancelar juntas: todas las operaciones quedan en
suspenso hasta que se termina la transaccin. No se podrn ver desde ninguna otra transaccin, lo cual es una de las
mayores sorpresas cuando uno empieza a trabajar de esta manera (si no tenemos esto en cuenta, los cambios realizados
en una estacin no se vern desde otra hasta que se cierre y se vuelva a abrir la aplicacin).
Las transacciones deben tener los siguientes atributos, reconocidos generalmente el acrnimo ACID, por sus iniciales
en ingls:

A por Atomicity (Atomicidad). Las operaciones incluidas en una transaccin se manejan como un todo
indivisible. Todas las operaciones se aceptan juntas, o ninguna.

C por Consistency (Consistencia). Las transacciones siempre llevan la base de datos desde un estado
consistente a otro; no pueden quedar datos inconsistentes, por ejemplo dos registros en la misma tabla con el
mismo valor en la clave primaria. Si pueden darse inconsistencias durante el desarrollo de una transaccin; pero las
dems transacciones simultneas que existan no vern este estado, y todas las inconsistencias debern resolverse al
momento de terminar la transaccin.

I por Isolation (aIslamiento). Cada transaccin se ejecuta como si estuviera sola en la base de datos; los
cambios producidos por otras transacciones concurrentes no deben verse desde las dems.

D por Durability (Durabilidad o persistencia). Una vez que una transaccin se acepta, sus cambios quedan
fijos en la base de datos an en caso de una falla del sistema o cada de la conexin. Como un corolario, tambin se

29/06/2012 02:33 a.m.

Firebird

10 de 76

[Link]

asegura que los cambios no se mantendrn en caso de una cada prematura del sistema, antes que la transaccin sea
aceptada con Commit.

La implementacin de transacciones de Firebird cumple con todas estas propiedades.

Debido al diseo de Firebird, todos los comandos deben ejecutarse en el contexto de una transaccin; si no la
controlamos nosotros, se empieza una automticamente antes de ejecutar cada comando y se termina tambin
automticamente al finalizar el comando. Cuando queremos agrupar varias acciones en una sola transaccin, debemos
comenzarla y terminarla explcitamente. La accin de aceptar todos los cambios de la transaccin se denomina en
ingls Commit, mientras que el proceso de rechazar los cambios, volviendo atrs todas las acciones realizadas, se
denomina Rollback.
El lenguaje de programacin de Firebird no tiene sentencias de manejo de transacciones; esto es as porque todos los
accesos a Interbase deben hacerse dentro del contexto de una transaccin, y no se aceptan transacciones anidadas. Es
decir que todos los procedimientos almacenados o triggers que puedan llegar a ejecutarse lo harn siempre dentro de la
transaccin del cliente que los ejecuta; en otras palabras, la responsabilidad es toda nuestra!
En base a lo discutido, podemos ya entrever algunos problemas comunes en las aplicaciones y sus causas:

Los datos se pierden al cerrar la aplicacin


Se aceptaron los cambios en la aplicacin, pero no se ha aceptado la transaccin. Los datos estn en suspenso en
la Base de Datos hasta que se ejecute Commit, de tal manera que si nuestra aplicacin no lo hace y cierra la
conexin, el servidor asumir que se produjo algn problema y har un Rollback automtico; todas las
modificaciones realizadas en esa transaccin se perdern..

Los cambios hechos en una estacin no se reflejan en otras que acceden simultneamente a los mismos datos
Esto es una consecuencia de las propiedades de Consistencia y Aislamiento. Como dijimos antes, las
modificaciones realizadas dentro de una transaccin deben ser aceptadas o canceladas en conjunto. Hasta ese
momento, quedan en un limbo informtico y nadie se enterar de su existencia. Incluso despus de terminada
correctamente una transaccin puede haber diferencias en lo que se ve en una y otra estacin de trabajo depende
del nivel de aislamiento de las distintas transacciones concurrentes, un tema que veremos en breve.

Problemas de bloqueos en registros que ya se modificaron


Cuando se trabaja con mltiples usuarios a la vez es importante mantener las transacciones de corta duracin. Por
qu? Porque como hemos visto, los otros usuarios no vern nuestros cambios hasta que cerremos nuestra
transaccin; pero adems, los registros modificados son bloqueados para la edicin desde otras terminales bloqueo
que se mantiene mientras dura la transaccin. Imaginemos que desde un puesto de venta se comienza una factura,
se actualiza el stock, y antes de terminar la transaccin el empleado se detiene a tomar un caf no se podrn
vender los mismos productos desde otras terminales hasta que vuelva y termine con su transaccin!
Tambin hay un problema con el recolector de basurade Firebird, pero ese problema es menos urgente que los
anteriores (se nota despus de un tiempo). En breve, el sistema recolector de basura de Firebird se activa despus
de N transacciones (un parmetro de configuracin del servidor) y se encarga de eliminar los objetos auxiliares que
crea el servidor mientras procesa los datos. Si dejamos pasar mucho tiempo sin que se active este sistema, se puede
ralentizar mucho la operacin del servidor.

Concurrencia 1: niveles de aislamiento de transacciones

29/06/2012 02:33 a.m.

Firebird

11 de 76

[Link]

[4]
Cuando se trabaja en modo multiusuario , accediendo desde varias estaciones a la misma Base de Datos, hay que
tener especial cuidado con las transacciones concurrentes de los clientes. El servidor define varios niveles de
aislamiento de transacciones concurrentes, que indican cmo se relacionan las transacciones simultneas entre s.
Como un ejemplo, consideremos la siguiente situacin: un usuario empieza una transaccin y hace algunos cambios.
Mientras todava su transaccin est activa, otro usuario empieza una segunda transaccin. El segundo usuario no ver
los cambios que realice el primero, a menos que est en el modo ms bajo de aislamiento (que no existe en Firebird,
ver a continuacin). Este comportamiento puede confundir al ms pintado, ya que posiblemente las dos transacciones
se hagan... en la misma mquina! Entonces sera posible realizar un cambio en una ventana y no verlo desde otra;
incluso re-ejecutando la consulta.

Los niveles de aislamiento de transacciones de Firebird son los siguientes:


read commited (lectura de lo aceptado): si estamos en una transaccin con este nivel de aislacin, podremos ver los
cambios de los dems cuando ellos terminen su transaccin con commit (nosotros tendremos que repetir la consulta, o
sea cerrar y volver a abrir el conjunto de datos). No es necesario que terminemos nuestra transaccin para ver las
modificaciones.
[5]
snapshot (lectura repetible ): se garantiza que el usuario que est en una transaccin de este tipo ver siempre los
mismos datos, aunque otros usuarios hagan cambios y los acepten. No veremos los cambios hasta que cerremos nuestra
transaccin y comencemos una nueva. Este nivel de aislamiento es ideal para los reportes, ya que en un entorno
multiusuario puede darse que cambien los datos entre el momento de la vista previa en pantalla y la impresin
propiamente dicha.
snapshot table stability (lectura repetible forzada): igual que la anterior, pero adems desde el momento que
accedemos a una tabla sta se bloquea para escritura. Este nivel es propio de Interbase, y no es muy usado porque
impone una restriccin muy severa a los otros usuarios, que slo estarn habilitados para leer de todas las tablas que
toquemos mientras estemos en la transaccin.

Hay un nivel ms de aislamiento que es comn en los sistemas de bases de datos locales: el llamado dirty read o de
lectura sucia. En este nivel se pueden ver los cambios de las dems transacciones, inmediatamente. Se pueden
producir problemas por leer datos que no han sido todava aceptados; si el usuario que hizo la modificacin finalmente
rechaza los cambios, hemos ledo datos inexistentes se denominan comnmente filas fantasma, phantom rows. Este
nivel no cumple con las propiedades de aislamiento y consistencia, por lo que no se permite en Firebird.

Concurrencia 2: modo de bloqueo de una transaccin

Cuando se modifica un registro desde una transaccin, ste se bloquea para modificaciones desde otra transaccin; el
bloqueo impide que se haga una segunda modificacin sobre los mismos datos mientras todava no se han aceptado o
rechazado los primeros.
Hay dos metodologas de bloqueo: optimista y pesimista.

Los servidores que implementan bloqueos pesimistas asumen que es muy probable que dos usuarios accedan
simultneamente a los datos para modificarlos; entonces toman una postura preventiva y cuando un usuario
empieza a editar un registro ste queda inmediatamente bloqueado para la edicin desde cualquier otra terminal.
Este modo de trabajo es muy comn en los sistemas de bases de datos de escritorio.

Los servidores SQL asumen en cambio que no es tan probable que se produzcan ediciones simultneas a los
mismos registros; basndose en este supuesto, solamente bloquea un registro cuando se ha realizado realmente una
modificacin en el mismo notificando a la base de datos mediante Post, por ejemplo. Note que no hemos
terminado todava la transaccin. Mientras tanto, el mismo registro puede estar siendo modificado en la memoria

29/06/2012 02:33 a.m.

Firebird

12 de 76

[Link]

interna de varias terminales a la vez. La primera terminal que guarde el registro (post) bloquea los cambios de las
dems. Cmo reaccionarn las aplicaciones que se encuentran con el bloqueo, depende de la configuracin de las
correspondientes transacciones como veremos a continuacin.

El parmetro que se indica cmo reaccionar una transaccin al encontrarse un registro bloqueado se denomina nivel de
bloqueo, y se configura al momento de comenzar la transaccin. Firebird tiene las siguientes opciones:

Modo en espera (WAIT): si hay un conflicto con otra transaccin (por ejemplo, las dos tratan de modificar el
mismo registro y aceptar los cambios), el ltimo proceso queda bloqueado hasta que se termina la primera
transaccin.

Modo sin espera (NO WAIT): si hay un conflicto con otra transaccin, el proceso recibe un mensaje de error
inmediatamente.

Cul es la razn de ser del primer modo? Pues que el conflicto puede ser temporal. Supongamos que un usuario (1)
empieza una transaccin en la cual agrega un registro con un valor A en la clave primaria. Antes que este usuario haga
Commit, otro usuario (2) trata de ingresar un registro tambin con el valor A en la clave primaria. Si la segunda
transaccin se hace en modo WAIT, el usuario 2 queda bloqueado hasta que el primero termine su transaccin. Si (1)
hace Commit, (2) recibe un mensaje de error porque la clave primaria estara duplicada; pero si (1) cancela su
transaccin con Rollback, (2) puede insertar su registro sin problemas. En el caso que la segunda transaccin fuera NO
WAIT, el usuario (2) recibe el mensaje de error al momento de querer insertar el registro, aunque luego (1) cancele los
cambios.

Los distintos modos de aislamiento junto con los niveles de bloqueo se configuran mediante parmetros en la llamada a
la API interna del servidor que comienza la transaccin. Podemos ver algunos ejemplos en la configuracin de los
niveles de aislamiento pre-configurados en los componentes Interbase Express (IBX):
Snapshot: no se ven los cambios realizados por las otras transacciones, pero se permite el acceso de las mismas a los
datos que estamos mirando o modificando; igualmente, podemos ver los datos que otra transaccin est trabajando al
mismo tiempo, aunque vemos la versin que exista al momento de iniciar nuestra transaccin. Parmetros por defecto:
concurrency, nowait. Ideal para reportes.

Read Commited: los cambios realizados por los otros usuarios se ven despus que acepten sus transacciones.
Parmetros por defecto: read_commited, rec_version, nowait.
El parmetro rec_version hace que slo veamos la ltima versin estable (aceptada) de los registros. La alternativa es
no_rec_version, con lo que indicamos al servidor que solamente se puede ver un registro si no hay versiones
pendientes de aceptacin (ms sobre esto luego, cuando tratemos la arquitectura multigeneracional). En el caso que
desde otra transaccin se haya modificado un registro pero todava no se haya realizado commit, el servidor no nos
dejara modificar el registro.

Read-Only Table Stability: esta transaccin no puede acceder a datos que hayan sido cambiados desde que empez,
ni permite a otras transacciones que accedan a los datos que sta haya ledo. Parmetros por defecto: read (slo lectura,
en este modo no se pueden modificar los datos), consistency (garantiza que los datos vistos por esta transaccin no
cambien, bloqueando los registros para escritura).

Read-Write Table Stability: igual que la anterior, pero ahora la transaccin bloquea los registros tanto para lectura

29/06/2012 02:33 a.m.

Firebird

13 de 76

[Link]

como para escritura. Parmetros por defecto: write, consistency.

Los modos ms usados son el Snapshot y el ReadCommitted, ya que permiten el acceso concurrente a los mismos
datos (sin bloqueos innecesarios).

Por ejemplo supongamos una tabla Mascotas con los siguientes datos:

Mascotas
Nombre

Categoria

Raza

Edad

Id

Lul

Perro

Caniche

89

Tom

Gato

Angora

908

Pinky

Ratn

Estupidis mousiis

346

Supongamos que esta base de datos se accede desde dos terminales a la vez, A y B. Veamos algunos casos tpicos (las
acciones se suponen en la secuencia dada). Para el caso no importa si usamos un componente IBTable, IBQuery con
IBUpdateSQL o un IBDataset. Indique despus de cada accin qu datos ve cada usuario:

A inicia una transaccin en modo Snapshot.

B inicia una transaccin en modo ReadCommitted y lee los datos de la tabla de mascotas.

A pide el contenido de la tabla Mascotas. Qu obtiene?


Lo mismo que est arriba

B modifica la tabla de mascotas, arreglando la edad de Tom que no es 3 sino 4. B hace Commit y vuelve a
abrir la tabla.
A ve lo mismo. B ve los datos de Tom modificados

A actualiza la vista de los datos cerrando y abriendo la tabla pertinente, pero sin salir de su transaccin.
A: lo mismo (no ve los cambios)

A modifica la edad de Lul, que no es 5 sino 4. Hace Commit y vuelve a abrir la tabla.
A ve ahora el cambio anterior de B. B todava no ve el cambio de A.

B cierra y abre la tabla.


Ahora B puede ver los cambios de A

B emite la instruccin Select * from Mascotas where Edad=4

29/06/2012 02:33 a.m.

Firebird

14 de 76

[Link]

B obtiene los datos de Lul y Tom.

B agrega un registro a la tabla de Mascotas, con los siguientes valores: Paco, Loro, Aptrida, 10, 79. Hace
Commit. A actualiza la vista cerrando y abriendo la tabla.
A no ve los cambios hasta que no cierre su propia transaccin.

A borra el registro de Tom. Hace Commit.


B tiene que cerrar y abrir la tabla para ver los cambios.

Qu pasa si B modifica el registro que A acaba de borrar?

Bloqueos pesimistas
A partir de Firebird 1.5, se puede usar un modo de bloqueo pesimista, indicando explcitamente en la sentencia
SELECT que se desea bloquear los registros resultado de la consulta. Veremos algunos ejemplos cuando estudiemos la
sentencia SELECT ms adelante; por ahora simplemente digamos que este agregado se hizo para simplificar la
solucin de algunos problemas. No es la forma recomendada de trabajar con los datos, y tiene adems varias
restricciones. Citando las notas de la versin 1.5:
"No est disponible en subconsultas, ni para joins. No se puede especificar con el operador DISTINCT, la clusula
GROUP BY o cualquier otra operacin de agregacin de registros. No puede utilizarse con o en una vista, ni con tablas
externas, ni con los resultados de un procedimiento almacenado llamado desde un SELECT."

Mantener el contexto
Una caracterstica que a veces es molesta: cuando cerramos una transaccin ya sea con Commit o con Rollback, se
cierran todos los controles de datos asociados a la misma. Firebird libera los recursos de la transaccin, por lo que los
componentes de datos se desconectan. Hay que volver a abrir uno por uno todos los componentes de acceso a datos que
trabajen con esa transaccin.
Para evitar el tener que abrir nuevamente todo, podemos indicar a Interbase que termine la transaccin pero que
mantenga los recursos internos -el contexto de la transaccin. De esta manera mantenemos los componentes conectados
aunque aceptamos o cancelamos la transaccin. Las operaciones se denominan CommitRetaining y
RollbackRetaining.
Hay un problema con esta manera de proceder: mientras no cerremos totalmente la transaccin, se evita que el
Recolector de Basura de Interbase trabaje. El accionar del servidor se vuelve ms lento por la proliferacin de
versiones la mayora ya obsoletas- de registros. Esto no debera ser un problema a menos que la aplicacin se
mantenga funcionando de esa manera durante horas, das, tal vez semanas... en cuyo caso podemos acomodar las cosas
haciendo una copia de seguridad (backup) seguida de una restauracin sobre la misma base (restore). Cuando se hace
un Backup se eliminan los datos temporales (la basura) y al recuperar la Base de Datos sta queda limpia de polvo y
paja.

Integridad referencial

29/06/2012 02:33 a.m.

Firebird

15 de 76

[Link]

La integridad referencial se refiere al estado de las referencias entre tablas. Es importante que las referencias se
mantengan, para asegurar que los datos se puedan acceder correctamente. Por ejemplo, si tenemos en una tabla los
datos de una factura, y en otra el detalle de los productos pedidos. En la tabla de detalle seguramente tendremos
solamente una referencia a la factura si hemos normalizado la base de datos. El valor del campo de referencia (por
ejemplo, el Nro de factura) se debe corresponder al valor de algn campo clave en la tabla de facturas, con lo cual
podemos recuperar el resto de los datos. Ahora pensemos qu sucedera si se modifica el valor del campo de enlace en
cualquiera de las puntas de la relacin.

Si modificamos el nro de factura en la tabla de detalle, estaremos referenciando a otra factura: esto puede estar
bien, de hecho es la nica manera de corregir un error en la asignacin.

Si modificamos el nro. de factura en la tabla de facturas, pues eso s puede representar un problema, ya que
todos los registros de detalle quedaran hurfanos, sin que sepamos a qu factura corresponden. Esto no se
puede permitir, ya que no tendremos forma de restaurar la relacin.

<<<Grfico con la relacin del ejemplo, con un diagrama E/R>>>

Las comprobaciones que impidan estos problemas y mantengan la integridad referencial se pueden llevar a cabo en el
cliente o en el servidor; hablaremos ahora de esta ltima opcin.
Firebird implementa la restriccin denominada clave externa en forma declarativa: se crea la restriccin como una
propiedad ms de una tabla, y el servidor se encargar de hacerla cumplir cuando sea necesario. En contraste, podemos
hacer un control activo escribiendo triggers que controlen explcitamente las referencias.
Las restricciones de clave externa (foreign key) se declaran en la tabla detalle de la relacin, en la tabla que referencia
a la maestra. En nuestro ejemplo, la tabla de facturas sera la maestra, y la de detalles
Para declarar una restriccin de clave externa necesitamos lo siguiente:

Un campo o conjunto de campos del mismo tipo en las dos tablas. Los valores de estos campos en la tabla detalle
referenciarn los valores de los campos correspondientes en la tabla maestra (el nro. de factura del detalle, en
nuestro ejemplo)

Una restriccin de unicidad sobre los campos de la relacin en la tabla maestra. Puede ser una clave primaria o una
restriccin UNIQUE; cualquiera de las dos posibilidades implica que los campos de la relacin deben ser
declarados como no null (no nulables).

NO es necesario un ndice sobre los campos de la tabla detalle; s es conveniente para acelerar las operaciones de
seleccin de datos sobre las dos tablas, por lo que Firebird crea un ndice automticamente sobre estos campos.

Firebird permite especificar la accin a tomar cuando se intenta violar la integridad referencial (por ejemplo cuando
borramos un cliente que est referenciado en una factura), tanto para las operaciones de borrado como de actualizacin.
Las opciones son (los nombres son parte de la sintaxis de la instruccin SQL de declaracin):

No action: la operacin se rechaza de plano.

Cascade: la accin se realiza tambin en los registros referenciados, automticamente. Por ejemplo si
cambiamos el nro. de un cliente y ste tiene hechas dos facturas, en las dos facturas se actualizar el nro. de
cliente para que la referencia siga siendo vlida. Si borramos el cliente, se borrarn las facturas que lo
referencian sin ningn aviso por parte del servidor, as que cuidado!

Null: el campo de la tabla maestra en el que se referencia al dato modificado o borrado toma el valor NULL, es
decir, pierde la referencia.

Default: el campo de la tabla maestra en el que se referencia al dato modificado o borrado toma el valor por
defecto declarado para ese campo.

Las ms usadas son las dos primeras. Firebird incluso nos permite indicar una accin para un caso y otra para el

29/06/2012 02:33 a.m.

Firebird

16 de 76

[Link]

restante, por ejemplo una combinacin muy usada es NoAction en borrados, Cascade en modificaciones. El servidor
entonces mantendr las referencias aunque cambiemos el campo en la tabla de detalle, mientras que impedir que
eliminemos registros de detalle que estn siendo referenciados.

Esta forma de mantener la integridad referencial es muy prctica y valiosa, aunque a veces lleva a un comportamiento
no ptimo en el que las operaciones llevan ms tiempo del necesario. Esto es debido a la selectividad de los ndices,
tema que trataremos ms adelante. En esos casos en que el comportamiento no sea el adecuado, tendremos que recurrir
a una verificacin activa de las relaciones usando triggers. Lo veremos tambin ms adelante.

En la prctica, las restricciones de integridad referencial se aplican generalmente cuando se va a poner en produccin el
sistema, no antes. Por qu? Pues porque el servidor no nos dejar modificar la estructura de una tabla que forme parte
de una restriccin de integridad referencial, y es muy comn que la estructura vare en el perodo de diseo y
programacin del sistema. As, se crean todas las tablas y dems objetos, se trabaja con esta base de datos, y finalmente
se agregan las restricciones para que no haya sorpresas. Es muy fcil generar un archivo script con las instrucciones
SQL necesarias para declarar las restricciones a posteriori de la creacin de las tablas. No obstante, hay que tener en
cuenta que las restricciones se comprueban en el momento de su declaracin esto es, si tenemos datos que no cumplan
con las restricciones no se podrn crear estas ltimas.

29/06/2012 02:33 a.m.

Firebird

17 de 76

[Link]

La instalacin y puesta en marcha de Firebird es muy simple. Se incluye un programa instalador al estilo experto que
nos guiar paso a paso en la instalacin; slo tendremos que seleccionar qu partes instalar y adnde.
A continuacin veremos el proceso completo desde la descarga de los archivos de Internet, la instalacin paso por paso
y daremos un primer saludo a las herramientas que se incluyen con el paquete.

Descarga desde Internet


Firebird es de cdigo abierto, y como tal se lo puede encontrar en Internet para su descarga libre y gratuita. No
obstante, es un motivo comn de confusin la existencia de distintas versiones, tanto de Firebird como de Interbase.
Aqu tratar de aclarar el lo.
Se puede descargar el cdigo fuente de FB/IB, en cuyo caso ser necesario compilarlo, o bien el paquete de instalacin
ya compilado lo que denominaremos formato binario. El proceso de compilacin de los fuentes quedar para otros
escritos; aqu me limitar a hablar del gestor ya compilado.
El primer sitio donde Interbase estuvo disponible en su version Open Source fue, por supuesto, el de Borland. No he
podido verificar si sigue disponible, por lo que pienso que no.
Hay otro sitio relacionado con Interbase desde sus inicios: [Link] . Es una compaa canadiense que
desarrolla software usando herramientas de Borland. El primer grupo de soporte a usuarios de Firebird estuvo
localizado en sus servidores hasta que el presidente de la compaa, Robert Schiek, fue contratado por Borland donde
se desempaa ahora como administrador de la comunidad de Interbase ([Link] ). La lista de
soporte ahora funciona en Yahoo! Groups, pero todava hay un ndice de las preguntas y respuestas en Mers, que se
puede consultar con un buscador. En el sitio de la compaa se puede encontrar la versin 6.0.2 de Interbase Open, para
Windows y Linux.
Y llegamos a Firebird. El proyecto comenz apenas una semana despus de la liberacin de Interbase, en SourceForge
([Link] [ERC5] -donde todava se lo puede encontrar. El sitio oficial es ahora
[Link] , un sitio derivado de IBPhoenix ([Link] ), de donde se pueden obtener las
distintas versiones de Firebird as como herramientas, artculos, etc. La versin actual (estable) es la [Link][ERC8] , y
se puede descargar tambin una versin 1.5 Alpha (no para produccin, inestable y sin garantas). Se espera que pronto
se ponga en marcha la versin beta de Firebird 1.5.
Entonces, hagamos un resumen:

Versin

URL para descarga

Interbase 6.0.2

[Link]

Firebird 1.0.3

[Link]

Firebird 1.5.1

[Link]

La instalacin es muy sencilla cuando todo funciona :-P. en Windows, corremos el archivo ejecutable; en Linux,
instalamos el paquete rpm o bien ejecutamos el script si descargamos la version no compilada. Las opciones son
mnimas y se reducen a seleccionar los componentes a instalar. Cuando hay algun problema, bueno habr que
empezar a preguntar. El mejor lugar para encontrar respuestas es el foro de soporte firebird-support en
[Link].

29/06/2012 02:33 a.m.

Firebird

18 de 76

[Link]

Probar la instalacin
ISQL

Con la distribucin estndar de Firebird se incluye una utilidad para ejecutar sentencias SQL contra el servidor, y
mostrar sus resultados. Esta utilidad es de lnea de comandos y se encuentra en el archivo [Link].
Se puede usar isql para probar la instalacin del servidor de la siguiente manera:
Abra una ventana de terminal en la carpeta bin de la distribucin de Firebird
Ejecute el programa escribiendo isql
Isql responder con un indicador (prompt) especial 'SQL>' como se ve en la siguiente imagen:

Escriba
Connect "localhost:c:\archivos de programa\firebird\examples\[Link]" user
"sysdba" password "masterkey";

para conectar con la base de datos de ejemplo. Note que puede cortar la sentencia en dos o ms lneas
simplemente presionando <Enter>; isql indicar que una lnea contina una sentencia anterior cambiando el
indicador (prompt) por 'CON>'. Las sentencias se terminan con punto y coma (;).

Si la conexin se puede establecer, isql responder con un mensaje indicando que est ahora conectado a la base
de datos. A partir de ese momento se pueden ejecutar sentencias SQL sobre esa base de datos, o usar algunos
comandos especficos de isql como Show Tables. En la parte de herramientas hablaremos ms en profundidad
sobre la utilidad isql.

29/06/2012 02:33 a.m.

Firebird

19 de 76

[Link]

Herramientas
IBServer

IBGuardian

ISQL

Gbak

IBConsole

IBConsole es un producto realizado utilizando acceso directo a la API de Interbase (con los componentes IB Express,
de los que hablaremos luego), por lo que su rendimiento es muy bueno. Tambin es simple de usar y nos da la
posibilidad de realizar las tareas administrativas comunes como ser: creacin y destruccin de bases de datos;

29/06/2012 02:33 a.m.

Firebird

20 de 76

[Link]

administracin de usuarios y permisos; realizacin de backups; verificacin de integridad de la Base de Datos;


ejecucin de sentencias y scripts SQL, etc.
A partir de la versin 1.5 de Firebird esta utilidad no se incluye ms en la distribucin. Se puede encontrar en
[Link] en sus versiones para Windows y Linux; no obstante, no se recomienda IBConsole como
herramienta de administracin para bases de datos Firebird, en parte porque est compilado con el conjunto de
componentes IBX que no garantizan compatibilidad con las nuevas versiones de Firebird.

Accederemos a una Base de Datos de ejemplo que se incluye en el paquete (si no instal los ejemplos, hgalo ahora; la
base de datos de empleados utiliza tcnicas que vale la pena estudiar). Usaremos la base de datos llamada
[Link] o su versin internacional (que contiene caracteres no ingleses) llamada [Link]. Cualquiera de las
dos sirve para nuestros ejemplos porque lo nico que cambia es el contenido de las tablas, no su definicin.

Para usar la base de datos, debemos registrarla en IBConsole. Los pasos necesarios son los siguientes:

registrar el servidor local con la opcin correspondiente del


men Server

29/06/2012 02:33 a.m.

Firebird

21 de 76

[Link]

en el men contextual del rbol de objetos de la izquierda seleccionamos Register

en el cuadro de dilogo que aparece a continuacin, completamos la informacin de registro de la base de datos
y aceptamos. La nueva Base de Datos debera aparecer en el rbol de objetos.

Hasta ahora lo nico que hemos hecho es crear un alias para la Base de
Datos; es decir, registrar con IBConsole la ubicacin fsica del archivo y
los datos de conexin, as como un nombre ms descriptivo que el nombre
del archivo. Para acceder a los datos debemos conectarnos a la base de
datos. Normalmente en el momento del registro IBConsole conecta
automticamente con la base de datos, como podemos observar en el rbol
que se abre y el grfico de la BD tiene una marca verde.
De aqu en adelante, podemos conectarnos haciendo simplemente doble
Click sobre el nodo en el rbol o seleccionando la opcin pertinente del
men contextual.

El solo hecho de lograr la conexin ya indica que el servidor est


funcionando correctamente. Todava se pueden presentar problemas en el
acceso a travs de la red, pero nos ocuparemos de eso a su debido tiempo.

Ejecutar sentencias SQL en IBConsole


Para ejecutar cualquier sentencia SQL utilizamos la herramienta conocida como Interactive SQL. En IBConsole est
integrada al producto, y se accede desde el men Tools o el botn

. La ventana tiene el siguiente aspecto:

29/06/2012 02:33 a.m.

Firebird

22 de 76

[Link]

Las sentencias SQL se escriben en el editor superior, se ejecutan con CTRL+E o el botn
inmediatamente en la parte inferior (datos, plan de ejecucin y estadsticas de ejecucin).

, y el resultado se obtiene

Por ejemplo, la siguiente imagen muestra el resultado de pedir el contenido de la tabla employee:

IBOConsole

Esta herramienta es como un clon de IBConsole, pero construida con los componentes IB Objects. Es gratuita y se
puede descargar de <<<Ver el enlace real en IBPhoenix>>>, y en general es ms estable que las versiones de
IBConsole que he probado. Se maneja de la misma manera, la interfaz es prcticamente igual, y podemos esperar que

29/06/2012 02:33 a.m.

Firebird

23 de 76

[Link]

sea til con las nuevas versiones de Firebird, ya que los componentes IBO soportan todas las caractersticas de estos
servidores.

IB_SQL

29/06/2012 02:33 a.m.

Firebird

24 de 76

[Link]

El lenguaje de consulta
Tal vez el problema mayor que se presenta a los programadores viejos, los que usaban sistemas de datos orientados a
archivos como Clipper, Dbase o Cobol, sea el de cambiar la forma de acceder a los datos. Lo que antes requera
recorrer toda una tabla buscando coincidencias o armar tablas temporales con datos de distintas tablas relacionadas,
ahora se hace con una sola sentencia de un lenguaje especial diseado para eso: el Lenguaje Estructurado de Consulta o
SQL.
Una de las caractersticas que distinguen a este lenguaje es su orientacin a conjuntos de datos. As por ejemplo, en
SQL no pedimos recorre todos los registros y cuando encuentres uno cuyo campo Nombre comience con A, me lo
muestras; en su lugar, pedimos una tabla temporal formada por todos los registros que cumplan la condicion: el
campo Nombre empieza con A. Lleva un tiempo acostumbrarse a pensar en conjuntos de datos, pero se logra.
Trataremos aqu de dar la mayor cantidad posible de ejemplos y ejercicios para que esta forma de pensar se haga casi
natural.
SQL son las iniciales de Structured Query Language o Lenguaje Estructurado de Consulta. Es un lenguaje no
procedural inventado en IBM a principios de los aos 70, para implementar el modelo relacional de Codd. Inicialmente
se le llam SEQUEL (Structured English Query Language), luego pas a ser SEQUEL/2 y finalmente SQL (esperemos
que no siga la tendencia y en unos aos se termine llamando S). Hoy en da es el lenguaje de consulta ms utilizado por
los gestores de Bases de Datos de todos los tamaos, desde Dbase o Paradox pasando por Oracle, Informix o SQL
Server, hasta los gestores de datos utilizados en supercomputadoras.
Hay definidos tres estndares oficiales por el Instituto Nacional de Estndares Americano (American National
Standards Institute, ANSI): SQL-86, SQL-89 y SQL-92.
La mayora de los gestores de consultas implementan a su manera las recomendaciones del estndar. Estudiaremos
los comandos ms comunes, que se aplican a los motores de consulta ms utilizados, y cuando sea pertinente
comentaremos diferencias en distintos servidores.
A continuacin veremos en detalle el lenguaje SQL que implementa Firebird. Los ejemplos utilizan la base de datos de
ejemplo que viene con el servidor, llamada [Link], y se ejecutan en IBConsole o IBOConsole.

Cursores vs conjuntos
Los gestores de datos tipo Dbase o Paradox trabajaban con el concepto de cursor; el lenguaje SQL trabaja con
conjuntos.
Los cursores se pueden ver como una cinta sobre la que se encuentran los registros, con un sealador que se mueve
adelante y atrs para marcar el registro activo o actual. Las operaciones sobre ms de un registro se realizan recorriendo
el cursor con el sealador y actuando sobre los registros a medida que son sealados.

Veamos dos operaciones tpicas con este modelo:

Seleccin de un subconjunto de registros, que cumplen un criterio determinado, por ejemplo mostrar los productos
de un rubro

El sealador se posiciona en el primer registro; comprueba si ese registro cumple con el criterio; si lo cumple se
muestra, si no se saltea; el sealador pasa al siguiente registro, y repite la comparacin hasta que no hay ms registros
en el cursor.

29/06/2012 02:33 a.m.

Firebird

25 de 76

[Link]

Modificacin de un subconjunto de registros, por ejemplo modificar el precio de todos los productos de
determinado rubro

La operatoria es prcticamente la misma, slo que en lugar de mostrar los registros que cumplen el criterio se editan, se
cambia el precio, y se vuelven a grabar. Hay que tener en cuenta que si el cursor est ordenado por algn ndice, el
cambio puede hacer que los registros se reubiquen y el sealador seguir al registro que modific, por lo que puede ir
a parar al final del cursor, o recomenzar al principio! En el ejemplo de los precios, seguramente el orden ser por rubro
por lo que la modificacin de precios no afectar la posicin de los registros.

Un servidor SQL como Firebird, en cambio, trabajar sobre conjuntos de registros en una sola operacin. As, las
mismas operaciones del ejemplo anterior se haran mucho ms simples:

Seleccin de un subconjunto de registros que cumplen determinado criterio

Simplemente se emite una sentencia SELECT y el servidor generar un cursor compuesto solamente con los registros
que cumplen el criterio. Para mostrar estos registros se hace el mismo bucle anterior, pero solamente se recorren los
registros que cumplen el criterio.

Modificacin de un subconjunto de registros que cumplen un criterio

Se emite una sentencia UPDATE que incluye la operacin a realizar y el criterio de seleccin, y el servidor modificar
el subconjunto que cumpla el criterio sin ms intervencin nuestra.

Seleccin de registros: SELECT


La sentencia estrella de SQL es, sin ninguna duda, SELECT. Esta instruccin permite obtener datos de una o varias
tablas, con un poder y flexibilidad increbles. Si SQL no tuviera ms que esta instruccin, igualmente valdra la pena
aprenderlo.
[6]
La sintaxis bsica de SELECT es como sigue :

SELECT columnas | *
FROM tablas
[WHERE condicin]
[ORDER BY columnas]

29/06/2012 02:33 a.m.

Firebird

26 de 76

[Link]

Hay muchas variaciones y agregados sobre este esqueleto bsico, pero todo a su tiempo.
En palabras, esta instruccin devolver una tabla virtual compuesta por las columnas especificadas (el asterisco * se
reemplaza por todas las columnas de todas las tablas), con las filas de las tablas dadas que cumplan la condicin
(opcional), y todo ordenado por las columnas indicadas (opcional).
Por ejemplo, para obtener los nombres de los empleados podemos escribir:

SELECT FIRST_NAME
FROM EMPLOYEE

Y veremos en la ventana de ISQL:

La sentencia SQL desaparece del editor, que queda listo para escribir otra; pero puede recuperarse con el botn
o la opcin de men Query|Previous.

Algunas preguntas comunes a esta altura:


Importa si las instrucciones se escriben en maysculas o minsculas?
No. Para el servidor es lo mismo SELECT que select. En la parte que s hay que tener cuidado es en los
nombres de campos y tablas, ya que hay dialectos SQL que distinguen entre maysculas y minsculas. En
Firebird, con el dialecto 1 de SQL no hay diferencias; con dialecto 3, las hay nicamente cuando se usan los
nombres entre comillas dobles ().
En qu orden se recuperan los registros si no especificamos una clusula ORDER BY?
En orden natural, lo que significa que no podemos asegurar nada. El motor de consultas obtiene los datos en
el orden que sea ms eficiente.
Es posible indicar algn formato en el resultado, por ejemplo el ancho de las columnas?
No. El lenguaje SQL es un lenguaje de consulta, no considera la parte de presentacin de los resultados.
Se pueden usar espacios en los nombres de campos y tablas?
Depende del servidor. En Interbase, nicamente podemos usar espacios con Dialecto 3 y si encerramos el

29/06/2012 02:33 a.m.

Firebird

27 de 76

[Link]

nombre entre comillas dobles. Los servidores actuales tienden a ser consecuentes con esta norma: si est entre
comillas, puede contener cualquier caracter. No obstante, recomendamos no utilizar caracteres especiales ni
espacios debido a los potenciales problemas con los diferentes conjuntos de caracteres. En general se
reemplazan los espacios por el caracter de subrayado (underscore, _) como en el campo FIRST_NAME usado
en el ejemplo.

Vamos a extender la tabla de resultados para que muestre otras columnas: el apellido (last_name) y el pas de trabajo
(job_country). La sentencia queda como sigue

SELECT FIRST_NAME, LAST_NAME, JOB_COUNTRY


FROM EMPLOYEE

Cmo hara para que aparezca primero el apellido y despus el nombre?


Cuando queremos todas las columnas de la tabla en el resultado, en el mismo orden que estn definidas, podemos usar
el comodn * (asterisco):

SELECT *
FROM EMPLOYEE

Notemos en el resultado de esta sentencia que hay una columna la ltima- que combina el contenido de los campos
First_Name y Last_Name para mostrar el nombre completo. En el caso de esta tabla, este campo est definido as,
como un campo calculado por el servidor. Nosotros podemos lograr el mismo efecto usando operadores para construir
campos nuevos, no existentes en la tabla original.
Por ejemplo, vamos a mostrar una columna con el Nro. de empleado (emp_no), un guin, el nombre y el apellido:

SELECT emp_no || ' ' || first_name || ' ' || last_name


FROM employee

29/06/2012 02:33 a.m.

Firebird

[Link]

28 de 76

29/06/2012 02:33 a.m.

Firebird

29 de 76

[Link]

Hemos utilizado aqu el operador de concatenacin || (dos barras verticales), que permite juntar cadenas de
caracteres. El resultado es otra cadena. Notemos que podemos usar tanto nombres de campos como cadenas constantes,
con comillas simples.

Un problema comn cuando se utilizan columnas formadas por expresiones es el nombre de estas columnas. Por
ejemplo, la columna generada en el ejemplo anterior se llama F_1. Quin puso este nombre? El servidor. Es posible
cambiarlo? Si, asignando un alias al campo por medio de la partcula as:

SELECT emp_no || ' - ' || first_name || ' ' || last_name AS Empleado


FROM employee

Si ejecutan esta sentencia, vern el mismo resultado que antes pero ahora la columna se llama Empleado, lo cual es
mucho ms fcil de recordar.

Antes de continuar sumergindonos en las complejidades de SELECT, realice los siguientes ejercicios para afirmar lo
anterior.

Ejercicios
1) Obtenga los siguientes datos (y en este orden) de los empleados: Nombre, Apellido, Nro. de empleado, salario
y pas de trabajo.
2) Ahora muestre tres columnas llamadas Apellido, Nombre, Salario. En la primera muestre el apellido, en la
segunda el nombre, y en la tercera la informacin siguiente (los ngulos indican que es el nombre de un
campo):
<Job_code>, nivel <job_grade> (U$S <salary>)
3) De la tabla de proyectos: una columna llamada Proyecto con el siguiente formato
(<proj_id>) <proj_name>
otra columna con el tipo de producto (product), y una tercera con el Nro. de empleado del lder del proyecto
(team_leader)

Orden en la sala
El orden en que el servidor devuelve los datos depende de varios factores; en general, no se puede asumir un orden
determinado por lo que hay que indicarlo explcitamente usando la clusula ORDER BY.
La clusula ORDER BY es muy simple de usar: es seguida por una lista de campos (que deben figurar en la lista de
columnas a mostrar) por los que se ordenar.
Por ejemplo, para obtener datos de los empleados ordenados por pas de trabajo, podemos hacer

SELECT *
FROM employee
ORDER BY job_country

Como podrn ver, hay muchos empleados que trabajan en cada pas, que no guardan entre s un orden predecible. As,
si tenemos que buscar un empleado por nombre en el listado anterior suponiendo que sabemos en qu pas trabaja,

29/06/2012 02:33 a.m.

Firebird

30 de 76

[Link]

tendramos que recorrer todos los empleados de ese pas hasta encontrar el que buscamos.
Para simplificar la bsqueda, podemos indicar al servidor que queremos los resultados ordenados, si, por pas; pero ms
todava, el conjunto de empleados de cada pas lo queremos ordenado por apellido y nombre. Pruebe la siguiente
sentencia:

SELECT *
FROM employee
ORDER BY job_country, last_name, first_name

Ya se comienza a notar la potencia del lenguaje. Esta instruccin nos devuelve una tabla con todos los empleados
organizados por pas, dentro de cada pas por apellido, y si hay apellidos repetidos, se ordenan por nombre.
Una variacin posible es el sentido de la ordenacin: si es ascendente o descendente. Por defecto Firebird devuelve los
datos ordenados en forma ascendente; para indicar lo contrario agregamos la partcula desc despus del nombre del
campo de ordenacin. Por ejemplo,

SELECT *
FROM employee
ORDER BY job_country desc

Nos devolver los empleados ordenados en forma descendente por pas de trabajo.
Este modificador es vlido slo para la columna a la cual sigue; cada una de las columnas de ordenamiento debe tener
su indicador de direccin o se tomar el ascendente por defecto. Tambin se puede explicitar el orden ascendente
usando asc.

SELECT *
FROM employee
ORDER BY job_country desc, last_name asc, first_name desc

Devolver un conjunto ordenado por pas en forma descendente, dentro de cada pas los empleados se ordenarn por
apellido en forma ascendente, y si hay apellidos repetidos, se ordenarn por nombre en forma descendente.

NOTA: como veremos en los ejemplos siguientes, la clusula ORDER BY siempre se coloca al final de la instruccin,
despus de todas las dems clusulas optativas.

Filtrados y bsquedas
Todos los ejemplos que hemos hecho hasta ahora devuelven el total de los registros de la tabla en cuestin. Como se
habrn imaginado, el lenguaje SQL tiene una clusula que sirve para reducir el conjunto de registros resultado a un
subconjunto que cumpla con ciertas condiciones. Para hacer uso de esta opcin solamente tenemos que agregar a la
sentencia SELECTFROM la clusula WHERE <condicin>.
La condicin debe ser una expresin que devuelva un valor booleano: aquellos registros para los cuales la expresin se
evale a Verdadero aparecern en el conjunto resultado, el resto no.
Por ejemplo, si queremos un listado de los empleados que trabajan en Canada solamente, haramos

29/06/2012 02:33 a.m.

Firebird

31 de 76

[Link]

SELECT *
FROM employee
WHERE job_country = 'Canada'

Podemos ordenar el resultado agregando al final la clusula order by:

SELECT *
FROM employee
WHERE job_country = 'Canada'
ORDER BY last_name, first_name

Esta instruccin nos permitir encontrar rpidamente un empleado de Canad. Pero podemos tambin usar los
operadores lgicos para afinar la bsqueda; por ejemplo, si queremos ver los empleados de Canada de categora 4,
haramos

SELECT *
FROM employee
WHERE (job_country = 'Canada') AND (job_grade = 4)

Notemos que el 4 no est rodeado de comillas; es un nmero, no una cadena. Los parntesis no son necesarios en este
ejemplo, pero pueden servir para aclarar el orden de evaluacin.
El orden de evaluacin puede determinar el resultado de una expresin: por ejemplo, no es lo mismo evaluar 1+2*3 de
izquierda a derecha (1+2=3, 3*3=9) que asociando por precedencia como hacemos en matematicas: 1+(2*3) = 7. La
siguiente tabla indica el orden de precedencia de los operadores en Firebird. Algn servidor puede diferir con este
orden, pero en general todos lo consideran de la misma manera. La precedencia va de mayor a menor, ledos de arriba
hacia abajo (por ejemplo, se evala primero una concatenacin que una multiplicacin; pero esta ltima se evala antes
que una suma).

Tipo

Operador

Comentario

Cadenas

||

Concatenacin

Matemticos

Multiplicacin

Divisin

Suma

Resta

=, ==

Igualdad

<>,[ERC9] !=,
~=, ^=

Desigualdad

Comparacin

>
<
>=

Mayor
Menor
Mayor o igual

29/06/2012 02:33 a.m.

Firebird

32 de 76

[Link]

Tipo

Lgicos

Operador

Comentario

<=

Menor o igual

!>, ~>, ^>

No mayor

!<, ~<, ^<

No menor

NOT

Negacin

AND

Conjuncin (Y)

OR

Disjuncin (O)

Es muy importante conocer el orden de precedencia de los operadores, para no cometer errores que pueden ser muy
difciles de detectar. Por ejemplo, si el resultado de una consulta tiene 1000 registros usando el criterio WHERE n >
1+2*3 y 1010 registros usando el criterio WHERE n > (1+2)*3, cul es el correcto? No sera fcil decidirlo. Y si
deciden mal, y le entregan al jefe la lista de los empleados que cumplen la condicin errnea, y stos son despedidos
bueno, no digan que no les avis.

Ejercicios
1) Realizar una consulta que devuelva los nombres y apellidos de los empleados que cobran ms de U$S 100.000
(afortunados ellos).
2) Realizar una consulta que devuelva una tabla como la siguiente, con los datos ordenados por Pas, categora,
apellido y nombre:
Empleado

Pas

Categora

Salario

<first_name><espacio><last_name>

<job_country>

<job_grade>

<salary>

3) Agregar a la tabla anterior una columna con el cdigo de trabajo (job_code) entre las de Categora y Salario.
Llamar a la columna Codigo_trabajo.
4) Listar aquellos empleados que hayan sido contratados en 1990 (hire_date)

El ltimo ejercicio pone el dedo en una llaga: el manejo de fechas.

Fechas/Horas en SQL
Nuevamente, cada servidor tiene sus convenciones con respecto al formato de las fechas. En Firebird tenemos varios
tipos de campos para almacenar fechas y horas:

Dialecto 1
DATE: almacena fecha y hora, como dos nmeros enteros de 32 bits. Equivalente al tipo timestamp del dialecto 3

Dialecto 3
DATE: almacena una fecha como un nmero entero que representa la cantidad de das pasados desde el 1 de Enero de
100. Puede almacenar hasta el da 29 de febrero de 32768. Un valor 0 para la fecha indicar el da 17 de Noviembre de
1858.
TIME: almacena una hora como un nmero entero. El rango permitido va desde las 00:00 AM hasta las 23:59.9999

29/06/2012 02:33 a.m.

Firebird

33 de 76

[Link]

PM, esto es, [Link].5964 PM.


TIMESTAMP: almacena fecha y hora, como dos nmeros enteros de 32 bits; la parte de fecha es igual al tipo DATE,
la parte de hora igual a un campo de tipo TIME

Entonces, cmo podemos usar fechas en criterios de seleccin? Ciertamente, no calculando la cantidad de das
pasados desde el da cero, 17 de Noviembre de 1858. Firebird puede convertir un tipo de dato en otro, y
particularmente con las fechas hace la conversin automticamente si el formato del texto con la fecha coincide con
alguno de los reconocidos:
CCYY-MM-DD
MM-DD-CCYY MM-DD-YY
MMM-DD-CCYY MMM-DD-YY
DD-MMM-CCYY DD-MMM-YY
CCYY-MM-DD HH:Min:SS:nnnn
MM-DD-CCYY HH:Min:SS:nnnn MM-DD-YY HH:Min:SS:nnnn
MMM-DD-CCYY HH:Min:SS:nnnn MMM-DD-YY HH:Min:SS:nnnn
DD-MMM-CCYY HH:Min:SS:nnnn DD-MMM-YY HH:Min:SS:nnnn

donde
CC = siglo
YY = ao
MM = mes
DD = da
HH = hora
Min = minutos
SS = segundos
nnnn = milisegundos

El separador de las fechas puede ser '-', '/' o '.'. Para las fechas se puede usar el formato americano (MM/DD) o el
europeo ([Link]), reconocindose por el separador: el punto para el formato europeo, cualquier otro para el americano.
Por ejemplo, para ver todos los empleados contratados en 1990 podemos escribir:

SELECT *
FROM employee
WHERE (hire_date >= '1990-01-01')
AND (hire_date < '1991-01-01')

Se definen en Firebird algunas literales que son reemplazadas por los valores que representan en el momento de la
evaluacin:
NOW: fecha y hora actuales
TODAY: fecha actual
YESTERDAY: fecha de ayer
TOMORROW: fecha de maana
Estas literales se utilizan encerradas entre comillas simples, como en el siguiente ejemplo:

29/06/2012 02:33 a.m.

Firebird

34 de 76

[Link]

SELECT *
FROM employee
WHERE hire_date < 'TODAY'

Que nos devolver todos los empleados contratados antes del da de hoy.
Asimismo, cuando trabajamos en Dialecto 3 podemos usar las funciones current_date, current_time y current_datetime
(sin comillas) para referirnos a la fecha y hora actuales en los tres formatos: DATE, TIME y TIMESTAMP
respectivamente.
Podemos tener una idea del tratamiento que da Firebird a las fechas creando una tabla con un campo de cada tipo, y
probando los distintos valores. Las instrucciones de creacin e insercin no han sido explicadas an, pero considero
importante el ejemplo en este momento.
Vamos a crear una tabla llamada Prueba, con los siguientes campos:
Campo

Tipo de dato

Clave

Integer

Hora

Time

Fecha

Date

Todo

Timestamp

La sentencia SQL necesaria aparece en el cuadro de la derecha. No nos preocupemos por ahora de esta sentencia; lo
nico que tenemos que saber es que crear la tabla deseada. Ahora emitimos los siguientes comandos, uno por vez, para
llenar la tabla con datos:

INSERT INTO prueba VALUES (1,'09:00','TODAY','NOW')


INSERT INTO prueba VALUES (2,'10:00','YESTERDAY','yesterday')
INSERT INTO prueba VALUES (3,'11:00','tomorrow','time')
INSERT INTO prueba VALUES (4,'12:00',current_date,'now')
INSERT INTO prueba VALUES (5,'13:00','2002-05-24','now')
INSERT INTO prueba VALUES (5,'13:00','2002-05-24','2002-05-24 12:35')

Si ahora pedimos los datos introducidos, con un SELECT comn

SELECT *
FROM prueba

veremos cmo interpret Firebird cada uno de los literales y funciones usados, en cada tipo de campo. Tambin
podemos probar otras combinaciones para ganar un entendimiento mayor de las expresiones que son vlidas y las que
no.

Ejercicios
En la base de datos donde cre la tabla Pruebas anterior:

29/06/2012 02:33 a.m.

Firebird

35 de 76

[Link]

1) devuelva los registros donde <fecha> es menor que hoy


2) devuelva los registros donde <todo> es menor que el momento actual
3) devuelva los registros donde <fecha> sea igual a la fecha de ayer
4) devuelva los registros donde <hora> es menor que las 12 del medioda, ordenados por fecha

Criterios de seleccin
Hay una serie de funciones que se pueden usar en las expresiones de criterios de seleccin. Como de costumbre, estas
funciones dependen del servidor de bases de datos, y veremos aqu en detalle las de Firebird.

<campo> LIKE <cadena>: comparacin de cadenas con comodines. Es similar al operador de igualdad (=)
pero solamente puede usarse con cadenas y permite el uso del comodn % para indicar cualquier carcter (cero
o ms) y _ para reemplazar un solo carcter que sin embargo debe existir. Se distingue entre maysculas y
minsculas.

Por ejemplo, la siguiente sentencia devolver todos los empleados cuyo nombre empieza con A (mayscula):

SELECT *
FROM employee
WHERE first_name LIKE 'A%'

Mientras que la siguiente sentencia devolver todos los empleados que contengan una a minscula en cualquier
posicin de su apellido:

SELECT *
FROM employee
WHERE last_name LIKE '%a%'

Pruebe a cambiar la a de la condicin por una A.

<campo> STARTING WITH <cadena>: devuelve TRUE si la cadena comparada comienza con el valor

pasado. Es equivalente a LIKE <cadena%>; pero el optimizador de consultas puede usar un ndice (si existe) con
STARTING WITH, mientras que con LIKE no.

Como ejemplo, veamos el mismo ejemplo que antes: los empleados cuyo nombre comienza con A:

SELECT *
FROM employee
WHERE first_name STARTING WITH 'A'

<campo> CONTAINING <cadena>: devuelve TRUE si la cadena comparada contiene el valor dado. Es
equivalente a LIKE <%cadena%>, pero tiene la ventaja de poder usarse con campos BLOB.

Como ejemplo, veamos el mismo ejemplo que antes: los empleados cuyo apellido contiene una a:

29/06/2012 02:33 a.m.

Firebird

36 de 76

[Link]

SELECT *
FROM employee
WHERE last_name CONTAINING 'a'

Tambin existe la versin negada, es decir que devuelve TRUE cuando el valor NO contiene la cadena:

SELECT *
FROM employee
WHERE last_name NOT CONTAINING 'a'

<campo> BETWEEN <valor inferior> AND <valor superior>: devuelve TRUE cuando el valor

comparado (que puede ser de cualquier tipo salvo BLOB) se encuentra entre <valor inferior> y <valor superior>,
ambos inclusive. Estos lmites deben ser del mismo tipo que el valor a comparar.
Por ejemplo, la siguiente sentencia devolver los datos de los empleados que cobran entre U$S 50.000 y U$S 72.000:

SELECT *
FROM employee
WHERE salary BETWEEN 50000 AND 72000

La siguiente instruccin traer los empleados contratados en 1990 (equivalente a la que vimos en un ejemplo anterior):

SELECT *
FROM employee
WHERE hire_date BETWEEN '1990-01-01' AND '1990-12-31'

Y la siguiente recuperar todos los empleados cuyo nombre empiece con A, B o C:

SELECT *
FROM employee
WHERE first_name BETWEEN 'A' AND 'Cz'

Notemos el uso de Cz para el lmite superior; cualquier cadena que empiece con C y siga con un carcter comn
ser menor o igual que esta cadena, por lo que entran en la seleccin todos los apellidos comenzados en C.
La versin negada devuelve TRUE cuando el valor no est en el rango dado:

SELECT *
FROM employee
WHERE hire_date NOT BETWEEN '1990-01-01' AND '1990-12-31'

Devolver los empleados que no fueron contratados en 1990.

<campo> IN <conjunto>: devuelve TRUE si el valor existe en el conjunto dado. El conjunto puede ser

especificado por extensin, como una lista de valores separados por comas y encerrados entre parntesis, o como
una subconsulta que devuelva un solo campo del tipo correcto.

29/06/2012 02:33 a.m.

Firebird

37 de 76

[Link]

Por ejemplo, para ver aquellos empleados de USA, Canada y Alemania (Germany) podemos hacer:

SELECT *
FROM employee
WHERE job_country IN ('USA', 'Canada', 'Germany')

Mientras que para ver los empleados que son lderes de algn proyecto podramos hacer:

SELECT *
FROM employee
WHERE emp_no IN (
SELECT team_leader
FROM project)

La consulta interior, encerrada entre parntesis, se denomina subconsulta y es una poderosa posibilidad de SQL en la
que ahondaremos en breve.
Tambin existe la versin negada, como se habrn imaginado:

SELECT *
FROM employee
WHERE emp_no NOT IN (
SELECT team_leader
FROM project)

Devuelve los empleados que no son lderes de proyectos.

<campo> IS NULL: devuelve TRUE si el valor es nulo; tambin puede usarse la forma <valor> IS NOT
NULL, que devolver TRUE en el caso contrario. Estas instrucciones fueron creadas especialmente para lidiar
con los valores nulos, y generalmente no equivalen a comparar simplemente un campo con el valor NULL
aunque tambin depende del servidor. Veamos un par de ejemplos:

SELECT *
FROM employee
WHERE phone_ext IS NULL

Devuelve los empleados cuya extensin de telfono es desconocida. Pruebe a ejecutar la siguiente sentencia, que
parece ser equivalente:
SELECT *
FROM employee
WHERE phone_ext = NULL

Este comportamiento es parte de las extravagancias de los nulos, de las que hablaremos muchas veces.
Si queremos ver los que s tienen almacenada una extensin, haremos
SELECT *
FROM employee
WHERE phone_ext IS NOT NULL

29/06/2012 02:33 a.m.

Firebird

38 de 76

[Link]

(1.5) CASE
A partir de la versin 1.5 de Firebird, se puede generar una consulta condicional cuyas columnas tomarn valor en base
al resultado de la evaluacin de una expresin. La sintaxis es la siguiente:
Se pueden clasificar las sentencias CASE en dos formas:
1) simple: se define la expresin despus de la palabra CASE y los distintos valores se asignan en base a los distintos
resultados de la evaluacin de esta expresin
CASE < expresion valor >
<clausula WHEN simple>...
[ <clausula else> ]
END

<<<Ejemplo>>>

2) con bsqueda: para cada valor se especifica una expresin


CASE <clausula WHEN buscada>...
[ <clausula else> ]
END

<<<Ejemplo>>>

Funciones
Existen en todos los servidores algunas funciones que toman un parmetro entre parntesis -usualmente el contenido de
un campo- y devuelven el valor modificado. Se pueden usar tanto en la especificacin de las columnas a devolver como
en los criterios.
Firebird es bastante parco en cuanto a las funciones predefinidas; tenemos solamente un puado:

UPPER(<cadena>): devuelve la misma cadena con todos los caracteres en maysculas.


CAST(<valor> as <tipo>): convierte el valor al tipo dado si puede.
GEN_ID(<nombre generador>,<incremento>): incrementa el valor del generador en la cantidad pedida y

devuelve el resultado. El generador queda incrementado.


SUBSTRING(cadena FROM inicio [FOR n]): devuelve n caracteres de cadena a partir del caracter nro. inicio. Si
no se especifica la clusula FOR, se devuelven todos los caracteres desde inicio hasta el final.

<<<OJO: creo que hay un problema cuando se usan juegos de caracteres de ms de un byte ver los mensajes de los
foros de Firebird y probar con fss_unicode y iso8859_1>>>

29/06/2012 02:33 a.m.

Firebird

[Link]

En dialecto 3 disponemos de la funcin EXTRACT para obtener una parte de una fecha:
EXTRACT({year | month | day} FROM <campo fecha>)

Por ejemplo, para obtener los empleados que fueron contratados en el mes de enero (de cualquier ao) haramos

SELECT *
FROM employee
WHERE extract(month from hire_date) = 1
EMP_NO
FIRST_NAME
LAST_NAME
PHONE_EXT HIRE_DATE
-------------------------------------------------------------------11
K. J.
Weston
34
17/01/1990
20
Chris
Papadopoulos
887
01/01/1990
141
Pierre
Osborne
03/01/1994

(1.5) NULLIF(expr1,expr2) devuelve NULL si expr1 es igual a expr2, caso contrario devuelve expr1.
<<<Ejemplos>>>

(1.5) COALESCE(expr1, expr2, expr3, exprN) devuelve el valor de la primera expresin no nula.
<<<Ejemplos>>>

Funciones de agregacin
Las siguientes funciones operan sobre un conjunto de registros (que puede ser la tabla entera), devolviendo un solo
valor por cada grupo:
AVG(<campo>): devuelve el valor medio del campo en el grupo de registros considerado.
COUNT(<campo> | *): devuelve la cantidad de registros del grupo. Si usamos la primera versin, con el nombre de
un campo entre los parntesis, devolver la cantidad de filas en que este campo sea no nulo; la segunda versin, con un
asterisco, devuelve la cantidad total de registros del grupo. Si no se encuentra ninguna fila que cumpla con las
condiciones, devuelve 0.
COUNT(distinct <campo>): igual que el anterior, pero cuenta slo los registros con valores diferentes en el campo

pedido.
MAX(<campo>): devuelve el valor mximo del campo en el grupo.
MIN(<campo>): devuelve el valor mnimo del campo en el grupo.
SUM(<campo>): devuelve la suma de los valores del campo en el grupo. No considera los valores nulos. Si no

encuentra nada para sumar (no hay registros o todos son nulos) no devuelve 0, como uno esperara: simplemente
devuelve un nulo.
Por ejemplo, la consulta siguiente devolver el monto total de remuneraciones anuales, sumando el campo SALARY de
todos los registros de la tabla EMPLOYEE:
select sum(salary)
from employee

39 de 76

29/06/2012 02:33 a.m.

Firebird

40 de 76

[Link]

SUM
----------115522468

Pero SQL puede dar mucha ms informacin que esa; por ejemplo, sera bueno conocer el total pagado en sueldos por
departamento, es decir que la suma actuara sobre subconjuntos de registros.
Para especificar los lmites de cada subconjunto de registros usamos la clusula GROUP BY seguida de una expresin
sobre campos de la tabla. Los registros se agruparn segn los valores de esos campos, de manera que todos los
integrantes de un grupo tengan el mismo valor en esos campos. Por ejemplo, la consulta indicada antes de totales
pagados en salarios por departamento puede escribirse como sigue:
select sum(salary) as TotalPorDepto
from employee
group by dept_no
TOTALPORDEPTO
-------------266643
155262.5
130442.81
13480000
95779.69
110000

An mejor, podemos mostrar el nro. de departamento junto a cada total:


select dept_no as Depto, sum(salary) as TotalPorDepto
from employee
group by dept_no
DEPTO TOTALPORDEPTO
-------------------000
266643
100
155262.5
110
130442.81
115
13480000
120
95779.69
121
110000

Trate de visualizar mentalmente el resultado de la sentencia anterior sin la clusula ORDER BY. Si Ud. puede, lo
felicito; yo no sabra cmo armar las filas, mezclando nros. de departamento (que se repiten) y totales por cada
departamento diferente. El intrprete SQL tampoco lo sabe, y se queja amargamente:
select dept_no as Depto, sum(salary) as TotalPorDepto
from employee
Dynamic SQL Error
SQL error code = -104
invalid column reference

como hicimos antes, debemos especificar que los registros se agruparn por nro. de departamento; entonces si, cada fila
de la salida corresponde a un grupo y todos los registros del grupo tienen el mismo valor en dept_no, por lo que no

29/06/2012 02:33 a.m.

Firebird

41 de 76

[Link]

hay ambigedades.
La regla sintctica es, entonces:
??????

Suponga ahora que queremos ver solamente aquellos departamentos en los cuales se pagan ms de 250.000 dolares al
ao en sueldos. En este caso la restriccin no se puede aplicar con una clusula WHERE, ya que la condicin a cumplir
utiliza el total por departamento calculado sobre los subconjuntos. Para aplicar una condicin de filtrado despus del
agrupamiento de los registros, existe la partcula HAVING:

select dept_no as depto, sum(salary) as TotalPorDepto


from employee
group by dept_no
having sum(salary)>200000
DEPTO TOTALPORDEPTO
-------------------000
266643
115
13480000
123
390500
125
99000000
621
276739.5
623
287758.25
671
219465.19

Esos son todos los departamentos que cumplen con nuestra condicin.
Ahora cambiamos la pregunta: queremos saber cules son los sueldos que se pagan por departamento, pero solamente
en USA. Esta condicin s se debe aplicar registro por registro, ya que puede haber un departamento con empleados en
distintos pases. La sentencia resultante es:
select dept_no as depto, sum(salary) as TotalPorDepto
from employee
where job_country='USA'
group by dept_no
DEPTO TOTALPORDEPTO
-------------------000
266643
100
155262.5
110
130442.81
130
189042.94
180
107377.5
600
132900

Y finalmente, juntamos las dos condiciones: queremos ver los departamentos en los que se pagan ms de U$S 200000
en total, contando solamente los empleados que trabajan en USA:
select dept_no as depto, sum(salary) as TotalPorDepto
from employee
where job_country='USA'

29/06/2012 02:33 a.m.

Firebird

[Link]

group by dept_no
having sum(salary)>200000
DEPTO TOTALPORDEPTO
-------------------000
266643
621
276739.5
623
287758.25
671
219465.19

Solamente quedan esos departamentos despus de todos los filtros. Observe el orden de las distintas palabras clave en
la sentencia: este orden debe respetarse.
Como ejemplo final, veamos esta misma lista pero ordenada de mayor a menor por monto:
select dept_no as depto, sum(salary) as TotalPorDepto
from employee
where job_country='USA'
group by dept_no
having sum(salary)>200000
order by 2 desc

Note que usamos el ndice del campo de agregado. Hasta la versin 1.02 de Firebird sta era la nica manera de
hacerlo, ya que no se podan usar expresiones en la clusula ORDER BY. En Firebird 1.5 esto se ha corregido, por lo
que la sentencia anterior puede escribirse (igual que en la mayora de los gestores de Bases de Datos):
select dept_no as depto, sum(salary) as TotalPorDepto
from employee
where job_country='USA'
group by dept_no
having sum(salary)>200000
order by sum(salary) desc

Notemos la potencia del lenguaje; imagnese lo que tendra que hacer para obtener este resultado usando un cursor,
recorriendo los registros uno por uno

Subconsultas
Hay casos en los que no nos basta con una consulta de seleccin. Pensemos por ejemplo cmo podramos obtener una
tabla con registros en los que figure cierto valor, que se debe obtener de otra consulta. Un caso tpico se da en las
relaciones 'muchos-a-muchos', en las que tenemos dos tablas relacionadas entre s a travs de una tercera.
Por ejemplo, tomemos el caso de las tablas Employee y Project de la base de datos [Link] que hemos trabajado
antes. Estas tablas no se referencian entre s directamente: no hay un campo en la tabla de empleados que referencie a
un proyecto en particular si este fuera el caso, cada empleado podra estar solamente en un proyecto a la vez. Lo
mismo pasa con los proyectos: si hubiera un campo para almacenar un nmero de empleado, solamente ese empleado
podra estar en ese proyecto La situacin real es ms compleja. Los empleados pueden estar en ms de un proyecto,
y los proyectos pueden tener ms de un empleado. Para esto se necesita una tercera tabla que contenga las relaciones.
En [Link] esta tabla se llama Employee_Project.
La tabla Employee_Project tiene la siguiente estructura:

42 de 76

29/06/2012 02:33 a.m.

Firebird

43 de 76

[Link]

CREATE TABLE EMPLOYEE_PROJECT (


EMP_NO EMPNO NOT NULL,
PROJ_ID PROJNO NOT NULL,
PRIMARY KEY (EMP_NO,PROJ_ID)
);

Como vemos, solamente tiene dos campos: uno referencia a un empleado, el otro a un proyecto. Cada registro de esta
tabla relaciona a un empleado con un proyecto, y la clave primaria es la conjuncin de los dos campos para permitir
repeticiones en cualquiera de ellos por separado pero no en los dos juntos (un mismo empleado no se puede poner en
un mismo proyecto dos veces).
Ahora pensemos en la siguiente pregunta: cules son los nombres de los proyectos en los cuales participa Bruce
Young? Intente obtener una respuesta con SQL antes de seguir leyendo.
Podemos ejecutar la siguiente secuencia de acciones:
1) buscar el nro. de empleado de Bruce Young, ya que ste es el campo que existe en la tabla intermedia
Employee_Project. Es muy simple:
select emp_no
from employee
where first_name='Bruce'
and last_name='Young'
EMP_NO
----------4

2) buscar los proyectos en que participa este empleado:


select *
from employee_project
where emp_no=4
EMP_NO
PROJ_ID
------------------4
VBASE
4
MAPDB

3) obtener los nombres de los proyectos 'VBASE' y 'MAPDB'


select Proj_id,Proj_Name
from project
where proj_id in ('VBASE','MAPDB')
PROJ_ID PROJ_NAME
----------------------------VBASE
Video Database
MAPDB
MapBrowser port

Esto fue fcil, dir usted. S. Pero no resulta difcil encontrarse relaciones de este tipo en las que un registro de una
tabla se relaciona con cientos o miles de registros de la otra en ese caso, sera muy engorroso y tal vez imposible de
realizar en un tiempo prudencial la escritura de todos los 'ID' de la segunda tabla en el conjunto enviado al operador IN.
Esta es una de las aplicaciones de las subconsultas, como ya vimos en la seccin de los criterios de seleccin: el
argumento para el operador IN puede ser el resultado de una consulta. En este caso, quedara

29/06/2012 02:33 a.m.

Firebird

44 de 76

[Link]

select Proj_id,Proj_Name
from project
where proj_id in (select Proj_Id from employee_project where emp_no=4)
PROJ_ID PROJ_NAME
----------------------------VBASE
Video Database
MAPDB
MapBrowser port

El resultado es el mismo, como era de esperar. Lo que hemos hecho es juntar varios pasos en uno solo.
Y la pregunta de examen: se puede obtener el mismo resultado con una sola sentencia? El resultado es afirmativo. Se
pueden ejecutar todas las operaciones de seleccin en una sola como la siguiente:
select Proj_id,Proj_Name
from project
where proj_id in
(select Proj_Id from employee_project where emp_no=
(select emp_no from employee where first_name='Bruce' and last_name='Young')
)

Observe especialmente que cada subconsulta va encerrada entre parntesis.

Este no es, claro, el nico caso en que se utilizan las subconsultas. Prcticamente cualquier problema que requiera la
ejecucin de sentencias de seleccin intermedias, cuyos resultados luego se usarn para obtener la respuesta, se puede
escribir usando subconsultas.

Comparacin con el resultado de una subconsulta


Los siguientes operadores se pueden usar con subconsultas:
<valor> ALL <subconsulta>: devuelve TRUE si el valor es igual a todos los devueltos por la subconsulta
<value> ANY | SOME <subconsulta>: devuelve TRUE si el valor comparado es igual a alguno de los devueltos por la
subconsulta.
EXISTS <subconsulta>: devuelve TRUE si la subconsulta devuelve al menos una fila.

Ejemplo: determinar si hay al menos un proyecto en el que trabaje Leslie Johnson


select 'Si' as Hay_un_proyecto
from project
where exists
(select Proj_Id from employee_project where emp_no=8)
HAY_UN_PROYECTO
---------------Si
Si
Si
Si
Si
Si

29/06/2012 02:33 a.m.

Firebird

45 de 76

[Link]

Pruebe con un nro de empleado distinto, por ejemplo 1 (no existe) o 2 (no est asignado a ningn proyecto).
La respuesta es un tanto repetitiva el hecho es que se mostrar un 'Si' por cada proyecto existente en la tabla 'Project',
dado que la subconsulta no est relacionada con la consulta exterior. Entonces, por cada registro de la tabla Project se
evala la subconsulta y sta siempre es la misma, siempre da el mismo resultado. Veremos dos maneras de evitar las
repeticiones:
1) Usando una tabla con un solo registro en la consulta externa. En Firebird / Interbase existe una tabla as en
todas las bases de datos: es la que almacena caractersticas de la base de datos en s, y por consiguiente slo
tiene un registro. Se llama rdb$database. La consulta anterior quedaria de la siguiente manera
select 'Si' as Hay_un_proyecto
from rdb$database
where exists
(select Proj_Id from employee_project where emp_no=8)

Esta consulta devuelve un solo 'Si' si hay al menos un proyecto que contenga al empleado, y NULL en caso que no
haya ninguno. Es bastante eficiente ya que la subconsulta se ejecuta una sola vez.

2) Usando una subconsulta correlacionada. En este caso la subconsulta se relaciona con la consulta exterior a
travs de algn campo, con lo que la evaluacin de la subconsulta en cada registro de la exterior puede arrojar
un resultado diferente.
select 'Si' as Hay_un_proyecto
from project
where exists
(select Proj_Id
from employee_project
where emp_no = 8
and employee_project.Proj_Id = project.Proj_id)
HAY_UN_PROYECTO
---------------Si
Si
Si

El resultado puede tener varias lneas, una por cada proyecto al que est asignado el empleado. Esta consulta es
ms lenta que la anterior pero da una informacin extra: la cantidad de proyectos a los que est asignado el
empleado.

SINGULAR <subconsulta>: devuelve TRUE si la subconsulta devuelve exactamente una fila.

Uniones
Firebird permite la unin de varias consultas en una sola, usando la palabra clave UNION entre las consultas. El
resultado de la operacin es una sola tabla, entonces qu campos tendr esta tabla? Si en todas las consultas unidas
hay campos diferentes, cules de ellos se incluirn en el resultado? Bueno, para no complicar las cosas el estndar
SQL define que todas las consultas incluidas en una unin deben tener los mismos campos. O sea:

la misma cantidad de campos,

29/06/2012 02:33 a.m.

Firebird

46 de 76

[Link]

que se llamen igual,

estn en el mismo orden y

sean del mismo tipo.

Suena un poco restrictivo, pero siguen siendo muy tiles. Veamos algunos ejemplos.

<<<Ejemplos de uniones>>>

Consulta de varias tablas relacionadas


Hasta ahora hemos trabajado siempre con una sola tabla. Pero si seguimos las reglas de normalizacin tendremos que
dividir muchas veces los datos en varias tablas; por ejemplo, en la tabla de proyectos (projects) de la base de datos que
estamos usando existe un campo llamado team_leader, numrico. Numrico? Quiere decir que los lderes de
proyecto se reconocen por un nmero nicamente, no por el nombre y apellido como todo el mundo? Bueno,
justamente: ese nmero es el nmero de empleado de un registro de la tabla employee. Despus de todo, hasta los
lderes de proyecto son empleados!
<<<grfico de los datos en forma de arbol, a la derecha>>>
Veamos de otra manera la normalizacin de tablas: como un rbol. En este rbol el tronco es nuestra tabla principal, y
cada nueva rama es un registro de otra tabla con un enlace hacia el tronco. En el caso menos botnico de las bases de
datos relacionales el enlace viene dado por uno o ms campos que tendrn los mismos valores en las dos tablas. Para
acceder a todos los datos completos de un registro de la tabla principal (el tronco), debemos mostrar tambin los datos
de todas las ramas que cuelgan de l. Algo as como hachar el rbol y poner todas las ramas una al lado de la otra.
Este esquema no sera funcional sin un lenguaje de consulta que permita obtener datos de tablas relacionadas a la vez;
esto es lo que hace SELECT con las relaciones o encuentros (Joins).
Hay varias maneras de recuperar informacin de tablas relacionadas. Por ejemplo, podemos pedir que la BD nos
devuelva los datos de todas las compras (tabla de facturas) de nuestros clientes (cuyos datos estn en otra tabla); pero
qu pasar con los datos de los clientes que no han comprado nada todava y por lo tanto no tienen facturas? Bueno,
esto depende del tipo de encuentro que usemos al consultar como veremos en seguida.
En general, las relaciones siempre se hacen entre dos tablas; aunque puede haber varias de estas relaciones de pareja en
una sola instruccin SELECT.
[7]
Veremos primero la forma ms antigua , listando los nombres de todas las tablas intervinientes luego de FROM,
separadas por comas, y con las relaciones en la clusula WHERE:

SELECT columnas | *
FROM tabla1, tabla2, tabla3
[WHERE condicin]
[ORDER BY columnas]

Con un ejemplo se ver ms claro. En la base de datos [Link] tenemos varias tablas relacionadas, por ejemplo
las de empleados (datos generales de los empleados) y la de departamentos (datos de cada departamento de la
empresa). En la tabla de departamentos (Apartment) hay un campo que relaciona con la tabla de empleados: Mngr_No,

29/06/2012 02:33 a.m.

Firebird

47 de 76

[Link]

o nmero de empleado del encargado (Manager). Este nmero se relaciona con el campo Emp_no de la tabla de
empleados, de tal manera que cada departamento que tenga un encargado tendra en el campo Mngr_no su nmero de
empleado. Si queremos mostrar el nombre del departamento y el nombre de su encargado, tendremos que buscar en las
dos tablas. La siguiente es una manera de hacerlo en SQL:

SELECT [Link], employee.full_name


FROM employee, department
WHERE department.mngr_no = employee.emp_no
ORDER BY [Link]
DEPARTMENT
FULL_NAME
---------------------------------------------------------------Consumer Electronics Div. Cook, Kevin
Corporate Headquarters
Bender, Oliver H.
Customer Services
Williams, Randy
Customer Support
Young, Katherine
Engineering
Nelson, Robert

Esta instruccin nos devuelve la lista de todos los departamentos, y el nombre del encargado, ordenados por
departamento.

Un

momento! Pidan una lista de los departamentos ordenados, y comparen por ejemplo, pueden ver en el primer
resultado el departamento Marketing? Este es slo uno de los que faltan. La razn: el campo Mngr_No de esos
registros tiene un valor nulo, implicando que no hay un encargado asignado al departamento (o alguien se olvid de
cargarlo en la base de datos).
Moraleja: cuando se utiliza esta forma de relacin entre tablas (listado de las tablas en el FROM, condiciones de enlace
en WHERE) nicamente aparecen en el resultado los registros de las dos tablas en las cuales haya valores de enlace
coincidentes. Este tipo de encuentro entre tablas se denomina Encuentro Interno (INNER JOIN).

29/06/2012 02:33 a.m.

Firebird

[Link]

Ejercicio
Realice la misma consulta del ejemplo anterior, pero esta vez sin el criterio de seleccin (WHERE). qu obtiene?

La unin interna que acabamos de ver es muy peligrosa; primero porque no muestra todos los registros, y podemos
llevarnos un chasco imagnense que le llevan la lista generada por la primera consulta al jefe y ste busca el
departamento de marketing. Y segundo, porque si no especifican la relacin entre las tablas como un criterio de
seleccin (como en el ejercicio) entonces obtendrn lo que se denomina una Encuentro Natural o Cartesiano. En esta
unin se muestran todas las combinaciones de los registros de las tablas. Es decir que si una tabla tiene 10 registros y la
otra tiene 5, el resultado contendr 50 registros!
El problema de la unin cartesiana se ve fcilmente cuando pedimos la unin de tres o ms tablas y nos olvidamos de
alguna relacin. Por ejemplo, si queremos ver el nombre de los clientes, las ventas que se le han hecho a cada uno, y la
moneda que se utiliza en el pas de origen del cliente, necesitamos las tres tablas Customer (clientes), Country (pases)
y Sales (ventas):

SELECT [Link] as Cliente, [Link] as Moneda, s.order_date as FechaPedido,


s.order_status as Estado, [Link] as Pagado
FROM customer c, country pais, sales s
WHERE c.cust_no = s.cust_no
AND [Link] = [Link]
ORDER BY [Link]

Hay varias cosas para notar en la consulta anterior.


No aparecen todos los clientes. Esto ya era de esperar, no? Cules son los que aparecen?
Las relaciones entre las distintas tablas se unen entre s con AND, para indicar que se tienen que cumplir todas las
condiciones para que el registro aparezca en el resultado.

As se pueden agregar ms tablas, simplemente listndolas en el FROM y agregando una condicin al criterio de
seleccin con AND. Qu pasar si nos olvidamos de algn criterio? Pues que el servidor no emitir ningn error, y
generar una unin cartesiana con la tabla que dejemos suelta

Hay otras formas de combinacin de tablas. Podemos pedir al servidor que nos muestre todos los registros de una de las
tablas, y nicamente los valores de la otra tabla cuando haya una correspondencia. Se dice que se preserva una tabla, la
que se muestra completa.
Algunos servidores implementan estas combinaciones con variaciones de la sintaxis anterior, agregando nuevos
operadores a la sentencia where. Firebird en cambio sigue el estndar ANSI-92 en el que se propone una nueva forma
de especificar las combinaciones entre tablas, indicndolas en el FROM. La sintaxis completa sera

FROM <tabla1> {INNER | LEFT | RIGHT | FULL} JOIN <tabla2> ON <expresin con los campos
relacionados>

Escribamos algunos de los ejemplos anteriores con la nueva sintaxis:

SELECT [Link], employee.full_name


FROM employee, department
WHERE department.mngr_no = employee.emp_no
ORDER BY [Link]

48 de 76

29/06/2012 02:33 a.m.

Firebird

49 de 76

[Link]

Esta instruccin nos devuelve la lista de todos los departamentos, y el nombre del encargado, ordenados por
departamento. Con la nueva sintaxis, quedara:

SELECT [Link], employee.full_name


FROM employee INNER JOIN department ON department.mngr_no = employee.emp_no
ORDER BY [Link]

O veamos la siguiente, que trae los datos de los pedidos, clientes y pases
SELECT [Link] as Cliente, [Link] as Moneda, s.order_date as FechaPedido,
s.order_status as Estado, [Link] as Pagado
FROM customer c, country pais, sales s
WHERE c.cust_no = s.cust_no
AND [Link] = [Link]
ORDER BY [Link]

Con la nueva sintaxis:


SELECT [Link] as Cliente, [Link] as Moneda, s.order_date as FechaPedido,
s.order_status as Estado, [Link] as Pagado
FROM customer c
INNER JOIN country pais ON [Link] = [Link]
INNER JOIN sales s ON c.cust_no = s.cust_no
ORDER BY [Link]

La nueva sintaxis separa fsicamente los conceptos lgicos de relacin o encuentro y criterios de seleccin.

Volvamos sobre el primer ejemplo, donde traamos cada departamento con el nombre de su encargado. Notamos antes
que no se listan todos los departamentos cuando pedimos una unin interna, ya que hay departamentos que no tienen
encargado. Usando las extensiones a la sintaxis podemos pedir que se nos muestren todos los departamentos,
completando el registro con el nombre del encargado cuando ste exista:

SELECT [Link], employee.full_name


FROM employee
RIGHT JOIN department ON department.mngr_no = employee.emp_no
ORDER BY [Link]

DEPARTMENT
FULL_NAME
---------------------------------------------------------------Consumer Electronics Div. Cook, Kevin
Corporate Headquarters
Bender, Oliver H.
Customer Services
Williams, Randy
Customer Support
Young, Katherine
Engineering
Nelson, Robert
European Headquarters
Reeves, Roger
Field Office: Canada
Sutherland, Claudia
Field Office: East Coast Weston, K. J.
Field Office: France
Glon, Jacques

29/06/2012 02:33 a.m.

Firebird

50 de 76

[Link]

Field Office: Italy


Field Office: Japan
Field Office: Singapore
Field Office: Switzerland
Finance
Marketing
Pacific Rim Headquarters
Quality Assurance
Research and Development
Sales and Marketing
Software Development
Software Products Div.

Ferrari, Roberto
Yamamoto, Takashi
Osborne, Pierre
Steadman, Walter
Baldwin, Janet
Forest, Phil
Papadopoulos, Chris
MacDonald, Mary S.

Note los espacios vacos en la columna 'FULL_NAME' del nombre del encargado. Hemos utilizado aqu una unin a
derecha, es decir preservando la tabla de la derecha de la partcula JOIN (en este caso, department).
Podemos reescribir la misma consulta, con el mismo resultado, preservando la tabla izquierda:

SELECT [Link], employee.full_name


FROM department
LEFT JOIN employee ON department.mngr_no = employee.emp_no
ORDER BY [Link]

Notemos que el resultado es el mismo, solamente hemos cambiado el orden de las tablas en la clusula FROM.
Por ltimo, podemos preservar las dos tablas al mismo tiempo: se mostrarn todos los registros de ambas tablas,
completando con nulos los lugares donde falten datos relacionados:

SELECT [Link], employee.full_name


FROM department
FULL JOIN employee ON department.mngr_no = employee.emp_no
ORDER BY [Link]
DEPARTMENT
FULL_NAME
---------------------------------------------------------------Consumer Electronics Div. Cook, Kevin
Corporate Headquarters
Bender, Oliver H.
Customer Services
Williams, Randy
Customer Support
Young, Katherine
Engineering
Nelson, Robert
European Headquarters
Reeves, Roger
Field Office: Canada
Sutherland, Claudia
Field Office: East Coast Weston, K. J.
Field Office: France
Glon, Jacques
Field Office: Italy
Ferrari, Roberto
Field Office: Japan
Yamamoto, Takashi
Field Office: Singapore
Field Office: Switzerland Osborne, Pierre
Finance
Steadman, Walter
Marketing
Pacific Rim Headquarters Baldwin, Janet
Quality Assurance
Forest, Phil
Research and Development Papadopoulos, Chris
Sales and Marketing
MacDonald, Mary S.
Software Development
Software Products Div.

29/06/2012 02:33 a.m.

Firebird

51 de 76

[Link]

Green, T.J.
Nordstrom, Carol
Bishop, Dana
Guckenheimer, Mark
Page, Mary
Johnson, Scott
Burbank, Jennifer M.
Brown, Kelly
Johnson, Leslie
Phong, Leslie
Fisher, Pete
Lee, Terri
Parker, Bill
Lambert, Kim
Yanowski, Michael
Stansbury, Willie
Bennet, Ann
Montgomery, John
De Souza, Roger
Young, Bruce
Ramanathan, Ashok
Hall, Stewart
Leung, Luke
O'Brien, Sue Anne
Ichida, Yuki

Ahora tenemos espacios vacos (recordemos que son valores nulos) en ambas columnas. Este tipo de consultas sirve
para ubicar rpidamente registros hurfanos, que han quedado desenlazados de la tabla maestra en una relacin
maestro-detalle. Recordemos que se pueden declarar restricciones de clave externa para evitar esto.
<<<Poner algn otro ejemplo de las uniones externas>>>

29/06/2012 02:33 a.m.

Firebird

52 de 76

[Link]

Lenguaje de Definicin de Datos (DDL)

El Lenguaje de Definicin de Datos es un subconjunto de SQL con instrucciones para crear, modificar y borrar los
distintos objetos que componen la Base de Datos como ser tablas, ndices, dominios, etc. Incluso permiten la definicin
de Bases de Datos completas.

Bases de Datos

Creacin de una base de datos


Para crear una base de datos se utiliza la sentencia CREATE DATABASE. La sintaxis es la siguiente:

CREATE {DATABASE | SCHEMA} 'filespec'


[USER 'username' [PASSWORD 'password']]
[PAGE_SIZE [=] int]
[LENGTH [=] int [PAGE[S]]]
[DEFAULT CHARACTER SET charset]
[<secondary_file>];

SCHEMA = equivalente a DATABASE


<secondary_file> = FILE 'filespec' [<fileinfo>] [<secondary_file>]
<fileinfo> = [LENGTH [=] int [PAGE[S]] | STARTING [AT [PAGE]] int }
[<fileinfo>]

Veremos las distintas opciones de la sentencia anterior a travs de ejemplos.

1. CREATE DATABASE C:\[Link] USER SYSDBA PASSWORD masterkey;

Esta es la instruccin ms comn: crea un archivo con el nombre dado como primer parmetro, conectando al servidor
con el nombre de usuario y clave dados (el usuario usado debe tener permisos para creacin de bases de datos
utilizaremos casi siempre el nombre del administrador del servidor, que por defecto es SYSDBA con clave
masterkey).
Si ya existe un archivo con el nombre pedido se cancela la operacin.
No es obligatoria la extensin .GDB

[8]

en el archivo; el motor de datos no considera la extensin sino el contenido.

29/06/2012 02:33 a.m.

Firebird

53 de 76

[Link]

El tamao no importa (perdn, Godzilla!)


El tamao de las bases de datos Firebird es dinmico; el servidor va agregando pginas (a continuacin) al archivo a
medida que las necesita. Es posible indicar al servidor un tamao mximo para un archivo de la base de datos, siempre
que haya otros archivos a continuacin. Por ejemplo, en la sentencia anterior podramos agregar LENGHT 10000 para
indicar al servidor un tamao mximo de 10000 pginas; pero al tratarse del ltimo archivo de la base (de hecho, el
nico) el servidor ignorar la indicacin y considerar al archivo como de tamao dinmico.
En ejemplos posteriores partiremos una base de datos en varios archivos, caso en el que s se respeta el tamao de cada
archivo salvo el ltimo.

2. CREATE DATABASE C:\[Link] USER SYSDBA PASSWORD masterkey PAGE_SIZE


4096;

Crea la misma base de datos que el ejemplo anterior, pero instruye al servidor para que utilice pginas de 4096 bytes en
lugar de 1024, que es el valor por defecto. Con esta configuracin se alcanza un mejor rendimiento, como se explica a
continuacin.

Pginas
Los registros dentro de las tablas se organizan en conjuntos llamados pginas. Las pginas son la unidad de
intercambio de datos entre el archivo en disco y la memoria; cuando el servidor necesita datos tiene que cargar una
pgina entera a la memoria. Estas pginas se mantienen en la memoria por un tiempo, de manera que estn rpidamente
disponibles si se solicitan nuevamente. La divisin en pginas es vlida tanto para datos como para los ndices.
El tamao por defecto de 1024 bytes es muy conservador de memoria; en los sistemas actuales, se alcanza un
rendimiento mucho mayor usando pginas de 4096 bytes o ms (Interbase soporta hasta pginas de 8192 bytes;
Firebird, 16384 bytes). Mientras ms grandes las pginas, ms memoria se usar en el servidor pero sern necesarias
menos lecturas de disco. El punto ptimo es un compromiso entre los recursos usados y el rendimiento necesario para
la aplicacin en consideracin.

3. CREATE DATABASE C:\[Link] USER SYSDBA PASSWORD masterkey PAGE_SIZE


4096 FILE c:\[Link] STARTING AT PAGE 10001;

Esta instruccin crea una base de datos dividida en dos archivos: el principal, c:\[Link], de hasta
40.960.000 bytes (4096*10000, unos 40 Mb) y otro secundario llamado c:\[Link] que almacenar las
pginas a partir de la 10001.
Una forma equivalente de definir la misma base de datos sera la siguiente:
CREATE DATABASE C:\[Link] USER SYSDBA PASSWORD masterkey PAGE_SIZE=4096
LENGHT=10000 PAGES FILE c:\[Link];

Note tambin que los signos = (igual), as como la palabra PAGES, son opcionales.
Cuando se especifican varios archivos, es importante tener en cuenta que en los archivos secundarios no se pueden
incluir nombres de nodos de red; por lo tanto, si se crea la base de datos de forma remota, todos los archivos
secundarios se crearn en el mismo nodo.

29/06/2012 02:33 a.m.

Firebird

54 de 76

[Link]

4. CREATE DATABASE C:\[Link] USER SYSDBA PASSWORD masterkey DEFAULT


CHARACTER SET 'ISO8859_1';

Esta ltima sentencia especifica un juego de caracteres por defecto para la Base de Datos.

El juego de caracteres
El juego de caracteres de una base de datos determina los caracteres a usar en las columnas de tipo CHAR, VARCHAR
o BLOB subtipo 1. Ligado al juego de caracteres estar tambin el tamao de almacenamiento, ya que por ejemplo el
juego UNICODE_FSS tiene caracteres que ocupan 1 byte y otros que ocupan hasta 3 bytes.
Tambin acta en el ordenamiento (collation order) y determina las transformaciones que se pueden hacer entre
distintos juegos de caracteres (transliteration). Para ver los distintos juegos de caracteres y las especificaciones de
ordenamiento (collation orders) disponibles, podemos interrogar a las tablas de sistema:

SELECT RDB$CHARACTER_SET_NAME, RDB$CHARACTER_SET_ID


FROM RDB$CHARACTER_SETS
ORDER BY RDB$CHARACTER_SET_NAME;
SELECT RDB$COLLATION_NAME, RDB$CHARACTER_SET_ID
FROM RDB$COLLATIONS
ORDER BY RDB$COLLATION_NAME;

En el ejemplo anterior (4) se especifica el juego de caracteres ISO8859_1 para ser usado por defecto; no obstante, se
puede cambiar en forma individual para cada campo alfanumrico de una tabla.
Si no se especifica el juego de caracteres por defecto, se tomar como NONE; esto significa que no se har ninguna
conversin al almacenar caracteres en los campos alfanumricos. Pero mucho cuidado: no se podrn copiar cadenas
entre campos definidos con NONE y otros definidos con un juego de caracteres diferente. Esto restringe la utilizacin
futura de distintos juegos de caracteres en campos especficos de una tabla.
Los clientes pueden especificar tambin el juego de caracteres con el que trabajarn, emitiendo una sentencia SET
NAMES <juego de caracteres> antes de trabajar con los campos alfanumricos. Esto le indica al servidor las
transformaciones que debe efectuar en los caracteres que se pasan entre el servidor y el cliente, en ambos sentidos.
Si no especificamos un juego de caracteres para el cliente, se tomar NONE por defecto. La restriccin que
comentamos antes de no poder convertir caracteres extendidos entre NONE y cualquier otro se mantiene, por lo que el
servidor rechazar cualquier intento de introducir caracteres extendidos en una tabla.
Podemos enunciarlo como
Regla Prctica: al acceder a una BD con un juego de caracteres distinto de NONE, el cliente tambin debera indicar
un juego de caracteres distinto de NONE, preferentemente el mismo que la BD.
Es muy comn encontrarse con el siguiente problema: a pesar de haber definido el juego de caracteres iso8859_1 por
defecto para la base de datos, cuando se quiere ingresar una cadena con ees o vocales acentuadas el servidor se queja y
rechaza el ingreso. Como podr imaginarse si ha ledo lo anterior con atencin, falta definir el juego de caracteres en la
conexin del cliente. Si est ejecutando un script SQL, agregue la sentencia SET NAMES iso8859_1; al principio. Si es
un programa, defina el juego de caracteres de la conexin segn lo requiera su lenguaje de programacin.

Un juego de caracteres puede soportar varias especificaciones de ordenamiento (collation orders). Por ejemplo, el juego
de caracteres ISO8859_1 usado para los caracteres europeos puede ser ordenado segn especificaciones francesas
(COLLATE FR_CA) o espaolas (COLLATE ES_ES). Las distintas opciones se obtienen de las tablas de sistema como se

29/06/2012 02:33 a.m.

indic antes. Este es el resultado en un servidor Firebird 1.0 mediante la siguiente sentencia (una mezcla de las dos
anteriores):
<<<Determinar que diferencia hay entre los ordenamientos fr_ca y es_es, con un ejemplo>>>

SELECT [Link]$CHARACTER_SET_NAME, [Link]$COLLATION_NAME


FROM RDB$CHARACTER_SETS cs
left join RDB$COLLATIONS co on [Link]$CHARACTER_SET_ID=[Link]$CHARACTER_SET_ID
ORDER BY [Link]$CHARACTER_SET_NAME;

RDB$CHARACTER_SET_NAME

RDB$COLLATION_NAME

ASCII

ASCII

BIG_5

BIG_5

CYRL

DB_RUS
PDOX_CYRL
CYRL

DOS437

DB_UK437
DB_US437
DB_FRA437
DB_ITA437
DB_NLD437
DB_SVE437
DB_FIN437
DB_ESP437
DB_DEU437
PDOX_ASCII
PDOX_INTL
PDOX_SWEDFIN
DOS437

DOS850

DB_UK850

También podría gustarte