38
S Q L Óscar Javier Segura Amorós [email protected] Cedida su publicación a el Rinconcito de Delphi No está autorizada su reproducción sin permiso expreso de su autor

SQL y Firebird

Embed Size (px)

Citation preview

Page 1: SQL y Firebird

S Q LÓscar Javier Segura Amorós [email protected]

Cedida su publicación a el Rinconcito de Delphi

No está autorizada su reproducción sin permiso expreso de su autor

Page 2: SQL y Firebird

SQL. El lenguaje universal de las Bases deDatos.

Óscar Javier Segura Amorós - [email protected]

Vamos a conocer SQL, un lenguaje de definición ymanipulación utilizado por todas las grandes Bases

de Datos.

SQL (Standard Query Language, Lenguaje de consultas estándar o estructurado), es un lenguaje que nospermitirá operar con nuestras bases de datos de una forma sencilla y potente. Se encuentra muy difundido yes soportado por todos los grandes sistemas gestores de bases de datos como pueden ser: Oracle, Interbase,Microsoft, Informix, Sybase, etc. La gran ventaja que nos ofrece SQL frente a otras formas de trabajar es suestandarización, no es necesario que cuando nos encontramos ante diferentes sistemas gestores tengamosque aprender como funciona cada uno de ellos de una forma más o menos detallada, simplemente debemosconocer como se trabaja con SQL, ya que su sintaxis y estructuración sufre muy pocas variaciones de unsistema otro. Por lo tanto SQL nos ofrece una única forma de trabajar con independencia del sistema con elque tengamos que hacerlo, con el consiguiente ahorro de tiempo y energías por parte de programador.

Para comenzar a entender las grandes virtudes que tiene SQL y las interesantes facilidades yposibilidades que nos brinda, vamos a imaginar la siguiente situación. Imaginemos que hemos diseñado unabase de datos para un grupo de clientes. El diseño de ésta, lógicamente, debe de ser independiente delsistema gestor en el que vaya a funcionar, pero qué ocurre cuando llegamos al cliente con el diseño hecho ytenemos que montarlo. Si tenemos la suerte de conocer el sistema gestor que el cliente utiliza, no tenemosningún problema, pero qué pasa cuando no lo conocemos, perdemos mucho tiempo. Además, si la mismabase de datos la vamos a montar para diferentes clientes, lo normal es que nos encontremos con diferentesgestores. Pues este inconveniente, que en principio para el programador puede ser un problema, SQL nos loresuelve. Si conocemos SQL, podremos llegar al cliente con los scrips de SQL en los que tenemos ya escritostodas las sentencias necesarias para: crear la base de datos, crear todas las tablas y relaciones, todos los tiposde datos de las tablas, todas las reglas de validación y las consultas para informes, solamente nos restaráejecutar esos scrips en el servidor y trabajo finalizado. ¿Qué hemos conseguido? Hemos conseguido rapidez,eficiencia, que el cliente quede satisfecho y nos hemos ahorrado interminables momentos de problemasporque el sistema gestor que utiliza el cliente no terminamos de conocerlo muy bien. Qué maravilloso,¿verdad?. Bienvenidos a SQL.

Un poco de historia. SQL comenzó a ver la luz sobre el final de la década de los 70, implementado comoun prototipo por IBM y en 1979 aparece el primer sistema gestor de bases de datos que lo soporta, Oracle.Poco tiempo después, otros sistemas como DB2, Interbase, etc, también quisieron adoptar al nuevo reciénnacido. Ya en 1987, 1992, 1995, 1996 se le confirió la estandarización a través de las normas ISO, hasta laactualidad, en la que todo sistema SQL se basa en el estándar SQL-3 (ISO-99) en el que se le han añadidonuevas características como la creación de TADs (tipos abstractos de datos), reglas activas (triggers -disparadores), cursores sensitivos, operador de unión recursiva, etc.

Aunque todo el SQL está estandarizado, sí es cierto que encontramos pequeñas diferencias en la sintaxisde las sentencias en los diferentes sistemas gestores. Estas diferencias repito que son mínimas y una vezrealizados los scrips de SQL que, por ejemplo, diseñan una base de datos, tendremos que hacer muy pocasvariaciones si queremos que esos scrips se ejecuten en diferentes sistemas gestores Emplazo al lector parasiguientes artículos en los que abordaré las diferencias más notables entre los principales sistemas gestores debases de datos SQL, en los que trataré de orientarlo sobre la variaciones sintácticas con las que nos vamos aencontrar. Insisto de nuevo en que esas diferencias son mínimas, tan mínimas que no llegan a ser uninconveniente para la utilización de SQL.

Page 3: SQL y Firebird

Funcionamiento de las bases de datos SQL

Siempre que realicemos un aplicación que vaya a trabajar sobre una base de datos, ésta la situaremosdentro de un servidor de base de datos. El servidor puede ser una máquina dedicada, cuya única función seala de atender peticiones de sus clientes, devolviéndoles la información y ejecutando los procedimientosordenados por estos sobre la base de datos. O también el servidor puede ser la misma máquina sobre la quecorra la propia aplicación. Dependerá ya de la estructura e importancia del sistema informático sobre el quevaya a funcionar nuestra aplicación. Sea cual sea la fórmula que vayamos a utilizar, la forma de trabajar serála misma, la única diferencia será si trabajamos con un solo ordenador, que hará simultáneamente lasfunciones de servidor y cliente, o con una red de ordenadores en la que los clientes y el servidor, en principio,quedan definidos de una forma más clara.

Una vez que conocemos como se estructura una base de datos SQL vamos a ver, a grandes rasgos,cómo funciona, cómo se realiza la comunicación entre el servidor y el cliente. Vamos a verlo muy porencima, sin entrar en detalles, simplemente para entender la forma de trabajar.

El cliente tendrá instalado un cliente SQL y el servidor tendrá instalado un servidor de SQL. La base dedatos estará instalada en el servidor y será únicamente el servidor de SQL el que acceda a ésta. Cuandonuestra aplicación realice una llamada a una sentencia SQL no será ella quien la ejecute. Esa sentenciallamará al cliente de SQL que tenemos instalado en nuestra máquina y será él quien se ponga encomunicación con el servidor de SQL. Una vez que el servidor SQL ha recibido la petición del cliente laejecutará sobre la base de datos, y el resultado de la ejecución será devuelta al cliente que se la pasará a laaplicación. Es el funcionamiento clásico de una distribución cliente-servidor. No es el momento de ensalzarlas virtudes que tiene esta forma de trabajar, simplemente comentaré que tiene el inconveniente de la rapidez,es lógico que el tiempo que se necesita para realizar todo el proceso desde que la aplicación realiza la llamadaal cliente con la sentencia SQL hasta que éste le devuelve los datos, es mayor que si la aplicación trabajaradirectamente con la base de datos, de todas formas tampoco quiero dar la impresión de que el retardo detiempo es importante, porque es mínimo. Pero en contraposición encontramos muchas ventajas, sobre todocuando van a ser varios los usuarios que utilizando simultáneamente nuestra aplicación trabajen con la basede datos, ventajas como: la integridad de los datos, la recuperación ante fallos, las inevitables colisiones, lastransacciones, etc.

Las instrucciones de SQL

Las instrucciones de SQL las podemos dividir en dos grandes grupos: las instrucciones que trabajan conla estructura de los datos, Lenguaje de definición de datos (LDD), y las instrucciones que trabajan con losdatos en sí, Lenguaje de manipulación de datos (LMD).

El lenguaje de definición de datos nos permitirá: crear nuestra base de datos, los tipos de datos definidospor el usuario, las tablas, las reglas de validación de los datos y las relaciones. El lenguaje de manipulación dedatos nos permitirá: introducir, modificar y borrar datos, realizar consultas y definir nuestros procedimientos ytriggers o disparadores. Como podemos apreciar, tenemos aun mucho trabajo por delante, pero prometo queva a valer la pena el esfuerzo.

Comenzaremos conociendo las instrucciones de definición de datos y continuaremos viendo las demanipulación. Para hacer más fácil el aprendizaje vamos a trabajar sobre una hipotética base de datos. Unabase de datos sencilla que nos va a permitir reflejar las explicaciones que se realicen sobre SQL en unejemplo práctico. Este ejemplo lo iremos intercalando con otros pequeños ejemplos no relacionados con él,que sirvan para completar el lado práctico del aprendizaje.

A lo largo del presente artículo conoceremos las instrucciones de definición de datos, dejando para elpróximo las instrucciones de manipulación de esos datos. De todas formas, al final de esta entrega daremosuna pequeña pincelada a las instrucciones de manipulación para que el lector vaya introduciéndose un pocoen ellas y nos sirva de cierto avance o introducción para la parte de SQL, que de momento, nos vamos aquedar sin conocer.

Page 4: SQL y Firebird

Diseño de una base de datos

Aunque no es estrictamente el tema de este artículo voy a nombrar brevemente los pasos que debemosseguir cuando vamos a diseñar una base de datos. De la misma forma que ya he hecho anteriormente, vuelvoa emplazar al lector para siguientes artículos donde trataremos este tema con mucha más profundidad.

Cuando nos enfrentamos al diseño de una base de datos muchos programadores se lanzan directamenteal interfaz del sistema gestor a comenzar a introducir tablas, atributos y relaciones. Gran error, aunque nosencontremos en la era de las nuevas tecnologías debemos todavía comenzar nuestro trabajo con unos foliosen blanco y un lápiz, mejor gastar un poco de tiempo al principio que desesperarnos cuando estamosterminando el trabajo porque nos hemos dado cuenta que tenemos errores de diseño, normalmente estoserrores son muy difíciles de solucionar, cuando al no detectarlos previamente hemos basado todo nuestrodiseño y trabajo sobre ellos.

Cuando tenemos que realizar el diseño de una base de datos comenzaremos por reunirnos con el clientey que nos especifique con todo detalle como funciona el sistema que tenemos que informatizar. Esa reunión latendremos que repetir cuantas veces sea necesaria hasta que conozcamos perfectamente la problemática quetenemos que resolver. Una vez conozcamos perfectamente el sistema comenzaremos a diseñarnos sobrepapel el esquema lógico de nuestra base de datos. Existen muchas modelados para representar la realidadque queremos informatizar, aunque el más conocido y extendido es el Entidad Relación Extendido (EER). Nose trata mas que de una forma de representar nuestra base de datos a través de un dibujo, de forma quepodemos identificar rápidamente todos los componentes de la misma. En la “Figura 1” podemos ver el EERde nuestra base de datos.

Figura 1. Modelo lógico, esquema ERR, de nuestra base de datos de ejemplo, Facturación.

Una vez tenemos diseñada nuestra base de datos, utilizando por ejemplo el modelo EER, obtendremos deél las tablas, campos de cada una de ellas y relaciones. Al obtener los elementos de la base de datos delesquema lógico nos aseguramos una metodología, un formalismo y evitamos los errores de diseño típicos quesiempre aparecen cuando estos se realizan de forma intuitiva.

Una vez que ya tenemos las tablas, sus campos y relaciones, ya podemos con SQL generar lasinstrucciones de los scrips de creación y manipulación de la base de datos.

Page 5: SQL y Firebird

Base de datos Facturación

Del EER de nuestra base de datos Facturación obtenemos las siguientes tablas, campos y relaciones.

Tabla Clientes:

• DNI Caracter(9) (Clave Primaria)

• Nombre CaracterVariable(50)

• Direccion CaracterVariable(60)

• Ciudad CaracterVariable(30)

• CodigoPostal Caracter(5)

• Telefono Caracter(9)

Tabla Facturas

• Numero Entero (Clave Primaria)

• Fecha Fecha

• Total Flotante

• DNI Caracter(9) (Clave Ajena hacia Clientes)

Tabla LineasFactura• Numero Autoincremento (Clave Primaria)

• Factura Entero (Clave Ajena hacia Facturas) Valor no nulo

• Cantidad Entero

• Articulo Entero (Clave Ajena hacia Articulos) Valor no nulo

• Precio Flotante

• Total Flotante

Tabla Articulos

• Codigo Entero (Clave Primaria)

• Nombre CaracterVariable(40)

• PrecioCompra Flotante

• IVA Flotante

La Clave Ajena hace referencia a que el dato de ese campo deben o ser nulos, si es permitido que lo sea,o existir en la tabla a la que hace referencia dicho campo. Esta regla es conocida como la regla de laintegridad referencial. El concepto de Clave Primaria significa que el valor de dicho campo sirve de valor deidentificación de ese registro dentro de la tabla, de forma que el dato en él introducido no puede ser nulo niestar repetido en otro registro de la misma tabla.

En la tabla Clientes su Clave Primaria es el DNI (Documento Nacional de Identidad) porque todos losclientes son personas y por lo tanto todos tienen que tener un DNI, primera condición de la Clave Primaria,nunca puede ser nula, y además el DNI no se va a repetir nunca puesto que no existen dos iguales, segundacondición de la Clave Primaria.

Page 6: SQL y Firebird

El campo Total de la tabla Facturas se refiere al total de la factura. El campo Total de la tablaLineasFactura se refiere al total de cada una de las líneas. Ambos datos son del tipo flotante pensando en quela facturación que intentamos hacer va enfoca al Euro. Como el Euro tiene dos posiciones decimales nos esnecesario asignarle un flotante.

En la tabla Artículos el campo IVA (Impuesto sobre el Valor Añadido) hace referencia a este impuestoque cada uno de los artículos llevará. El dato del IVA es un porcentaje sobre el precio del artículo.

Si nos fijamos ya tenemos definidas las tablas, los campos de dichas tablas, junto con sus tipos de datos ylas relaciones que existen entre las diferentes tablas. Las relaciones las tenemos plasmadas a través de loscampos de Clave Ajena que nos indican con que tabla estará relacionado el campo que sufre la clave. Loscampos que llevan la característica de Valor no nulo nunca pueden dejarse en blanco. Si nos fijamos, estoscampos son Claves Ajenas, por lo tanto lo que estamos consiguiendo es obligando a que siempre exista larelación, es decir, si existe un registro en la tabla, este registro estará obligado a relacionarse con la otra tabla,porque el campo que sirve para relacionar ambas tablas nunca puede estar en blanco.

Convenciones de diseño y algún consejo previo

Voy a citar las normas de diseño que debemos seguir para trabajar con las bases de datos de SQL yalgún consejo que siempre nos vendrá bien seguir.

En el desarrollo de los siguientes apartados utilizaré la notación estándar que describo a continuación:

• MAYÚSCULAS Palabras clave de Transact-SQL.

• Cursiva Parámetros de la sintaxis de Transact-SQL.

• | (barra vertical) Separa los elementos de sintaxis con corchetes o llaves. Sólo se puede elegir unode los elementos.

• [ ] (corchetes) Elementos de sintaxis opcionales. No escriba los corchetes.

• { } (llaves) Elementos de sintaxis requeridos. No escriba las llaves.

• [,...n] Indica que el elemento anterior se puede repetir n veces. Los elementos se separanmediante comas.

• [ ...n] Indica que el elemento anterior se puede repetir n veces. Los elementos se separanmediante espacios en blanco.

• Negrita Nombre de bases de datos, tablas, índices, procedimientos almacenados, programas, tiposde datos y texto que deben escribirse exactamente como se muestra.

En el nombre de la base de datos, de una tabla, de una regla o de un tipo definido por el usuario, es deciren los elementos que el usuario crea y que por lo tanto debe de nombrar, no se pueden introducir espacios enblanco, lo normal es sustituir esos espacios en blanco por el carácter de subrayado ,'_', o comenzar lasiguiente palabra por una letra mayúscula. Ejemplo: Lineas Pedido, sería incorrecto, podríamos nombraresta tabla como Lineas_Pedido,o LineasPedido. A lo largo del artículo yo utilizaré cualquiera de las dosformas indistintamente, aunque lo adecuado es que se elija una forma y se mantenga durante todo el trabajo.

Para definir los CONSTRAINT, elemento que abordaremos más tarde, si define una clave primaria elnombre de esta tendrá la forma cp_nombre_tabla, si se trata de una clave alternativa su nombre serácal_nombre_tabla y si se trata de una clave ajena caj_nombre_tabla. Si existiera dentro de la misma tablamás de una clave del mismo tipo irían numeradas, cp_nombre_tabla1, cp_nombre_tabla2, ... .

Page 7: SQL y Firebird

Crear, conectarse y borrar una base de datos (CREATE DATABASE,CONNECT DATABASE, DROP DATABASE)

Cuando comenzamos a crear nuestra base de datos en el servidor, el primer paso del montaje es crear labase de datos. Hasta que no creamos la base de datos no podemos comenzar a crear las tablas y demáselementos. La creación de la base de datos se hará una única vez. Normalmente el proceso de creación sehace desde el entorno visual del sistema gestor pero no existe ningún inconveniente en hacerlo utilizandocomandos SQL. Si lo hacemos desde SQL el comando de creación es CREATE DATABASE, y susintaxis:

CREATE DATABASE nombre_base_datos

La sintaxis de CREATE DATABASE admite muchos más parámetros aunque normalmente no seutilizan.

En los sistemas gestores a la hora de crear nuestra base de datos debemos de estar situados en la basede datos del sistema, en la mayoría de los sistemas llamada master. Esto es así porque en ella se introducirála información de las propiedades de nuestra base de datos, la que terminamos de crear.

Una vez que hemos creado nuestra base de datos, proceso que debemos realizar solamente la primeravez, cada vez que queramos trabajar con ella tendremos que establecer la conexión entre nuestro cliente deSQL y el servidor de SQL. Este proceso, al igual que el proceso de creación, se suele realizar desde elinterfaz gráfico. Normalmente el sistema gestor nos ofrece un menú desplegable con todas las bases de datosexistentes donde seleccionamos la base de datos con la que vamos a trabajar. El comando SQL equivalente aeste proceso es CONNECT, y su sintaxis:

CONNECT DATABASE nombre_base_datos

Con el comando CONNECT sí vamos a encontrar diferencias importantes dependiendo del sistemagestor con el que trabajemos. Por ese motivo normalmente se realiza desde el interface gráfico.

Para borrar una base de datos, tan sencillo como:

DROP DATABASE nombre_base_datos

Crear tablas (CREATE TABLE)

Para crear las tablas utilizamos el comando CREATE TABLE, cuya sintaxis es:

CREATE TABLE nombre_tabla(

columna1 tipo_dato,columna2 tipo_dato,... ...,columnan tipo_dato,

CONSTRAINT cp_nombre_tabla PRIMARY KEY (columna1,...,columnan),[CONSTRAINT cal_nombre_tabla UNIQUE (columna1,...,columanan),[CONSTRAINT caj_nombre_tabla FOREIGN KEY (columna1,...,columnan) REFERENCES tabla]

)Las posibilidades de CREATE TABLE son muchas más de las que he mencionado en la lista anterior

pero realmente no son utilizadas.

Por defecto, cuando creamos una tabla todos los campos de la tabla admitirán valores nulos. En principioes lo adecuado. Solamente encontraremos problemas con los campos que sean claves primarias oalternativas, puesto que por definición estos campos siempre tiene que tener valor, nunca pueden estarvacíos. Por ello, en estas columnas estaremos obligados a añadirles la opción NOT NULL, que obliga a que

Page 8: SQL y Firebird

esos campos no admitan valores nulos. Esa opción también tendremos que utilizarla en los campos que seanclaves ajenas y estemos obligados a que todos los registros de nuestra tabla estén relacionados a través deesa clave ajena. La forma de utilización es muy sencilla:

columna1 tipo_dato NOT NULL,

Ahora vamos a conocer los tipos de datos que podemos aplicar a los campos. SQL nos ofrece granvariedad de tipos de datos, aunque como ocurre siempre, nos acostumbramos a utilizar unos pocos y si enalguna ocasión necesitamos plasmar alguna situación un poco más especial recurrimos a la ayuda de SQLpara ver más detalladamente otros tipos de datos o nos creamos los nuestros propios.

• Integer enteros comprendidos entre -231 (-2.147.483.648) y 231 - 1 (2.147.483.647).

• Smallint enteros comprendidos entre 215 (-32.768) y 215 - 1 (32.767).

• Tinyint enteros comprendidos 0 y 255.

• Real flotantes comprendidos entre -3,40E + 38 y 3,40E + 38.

• Datetime fechas.

• Char caracteres fijos hasta 8.000.

• Varchar caracteres variables hasta 8.000.

• Text caracteres variables hasta 231 - 1 (1.147.483.647).

Un pequeño comentario sobre los tipos de datos. La diferencia entre caracteres fijos (Char) y caracteresvariables (Varchar) estriba en que si nosotros hacemos con Char una reserva de memoria de 50 posiciones yal introducir datos solamente utilizamos 20, el resto será memoria desperdiciada, mientras que si hemosrealizado la reserva utilizando Varchar, caracteres variables, si al final solamente utilizamos 20, el resto dememoria será liberada. Lo más adecuado es utilizar siempre para caracteres Varchar, utilizando Charsolamente en aquellos casos en que sepamos de antemano que siempre se va a consumir todo el espacioreservado, como podrían ser campos como los números de teléfono, códigos de texto de tamaño fijo, etc.

Si en algún momento necesitamos tener un campo entero que sea autonumérico, es decir, que el sistemagestor vaya controlando su valor e incrementándolo o decrementándolo de forma automática, sin que nosotrostengamos que preocuparnos por ello, tenemos que utilizar la opción IDENTITY. Esta opción necesitará dosparámetros, la inicialización, el valor por el que tiene que comenzar, y el incremento, en el que indicamos elvalor de incremento, tanto si es positivo como negativo. Su sintaxis:

columna1 integer identity (1,1),

Según el ejemplo anterior, el campo columna1, será un autoincrementable que comenzará en el valor 1 eirá incrementando de uno en uno.

Y como no hay mejor forma de aprender que trabajando un poco, vamos a ver como serían loscomandos SQL para la creación de nuestras tablas de ejemplo.

Create table Clientes(

DNI char(9) not null,Nombre varchar(50),Direccion varchar(60),Ciudad varchar(30),CP char(5),Telefonochar(9),

constraint cp_Clientes primary key (DNI))

Page 9: SQL y Firebird

Fijémonos en la creación de tabla que acabamos de realizar, y destaquemos algunos detalles. El DNI esla clave primaria, así queda definido en la última línea de la instrucción de creación de la tabla, además, a estaclase, se le ha dado el nombre de cp_Clientes, como ya se había recomendado en el apartado deConvenciones de diseño. Si la clave primaria de nuestra tabla Clientes es el DNI, por definición este camponunca podrá contener valores nulos, por lo que vamos a tener que indicárselo, indicación que hacemos, talcomo se aprecia en el listado, añadiéndole al campo la opción NOT NULL.

create table Facturas(

Numero integer identity (1,1) not null,Fecha datetime,Total real,DNI char(9),

constraint cp_Facturas primary key (Numero),constraint caj_Facturas foreign key (DNI) references Clientes

)

En la creación de la tabla Facturas nos encontramos con el comando IDENTITY, que indica que elnúmero de factura se irá generando automáticamente comenzando por el número de factura 1 y creciendo deuno en uno. También nos encontramos la definición de una clave ajena, el campo DNI será una clave ajenaqe relacione una factura con un cliente.

create table Articulos(

Codigo integer not null,Nombre varchar(40),PrecioCompra real,IVA real,

constraint cp_Articulos primary key (Codigo))

create table LineasFactura(

Numero integer identity(1,1) not null,Factura integer not null,Cantidadinteger,Articulointeger not null,Precio real,Total real,

constraint cp_LineasFactura primary key (Numero),constraint caj_LineasFactura1 foreing key(Factura) references Facturas,constraint caj_LineasFactura2 foreing key(Articulo) references Articulos

)

Aquí nos encontramos con la existencia de dos claves ajenas, como podemos ver sus nombres son elmismo solamente que numerados para que no haya error. Además a los campos de estas dos claves ajenasse les ha asignado la característica de no poder tomar valores nulos. Por lo tanto, siempre que exista una líneade factura ésta va a tener que pertenecer a una factura y ser de la venta de un artículo, no pueden existirlíneas de factura que no cumplan estas condiciones.

En realidad el comando CONSTRAINT no es de obligado cumplimiento, podríamos definir claves, tantoajenas como primarias sin la necesidad de utilizar CONSTRAINT pero no podríamos darles un nombre adichas claves. En siguientes apartados veremos que inconveniente se nos plantea si tomamos ladeterminación de no dar nombre a nuestras claves.

Page 10: SQL y Firebird

Insercción, modificación y borrado de datos (INSERT,UPDATE,DELETE)

Una vez que ya tenemos creadas las tablas podemos comenzar a trabajar con los datos, insertando,modificando y borrando datos. ¿Que cómo?, pues lo vemos enseguida. A continuación la sintaxis de cada unode los procesos respectivamente:

INSERT INTO tabla [(columna1,...,columnan)] VALUES (valor1,...,valorn)UPDATE tabla SET columna1=valor1,...,columnan=valorn WHERE condicionDELETE FROM tabla WHERE condicion

Bueno, esta sintaxis parece más sencilla que la vista en el apartado anterior. El comando INSERT notiene ningún secreto, es muy sencilla su forma. Donde podemos encontrar algún problema es con laactualización y el borrado, problema en el sentido de entender y a posteriori determinar correctamente lacondición de la cláusula WHERE. Las filas de la tabla que cumplan la condición de la cláusula where serálas filas que sufran la actualización o el borrado dependiendo del comando utilizado. Vamos a unos ejemplos.

Insert into Clientes (DNI,Nombre,Direccion,Ciudad,CP,Telefono) values (“21547789”,”AgapitoLafuente Corral”,”c./La plaza nueva”,”Alicante”,”03005”,”987785655”)

Insert into Clientes (“12456445”,”Maria del mar Sanchez Juan”,”c./Lamarina”,”Madrid”,”25455”,”887452114)

En la segunda inserción se me ha olvidado poner los nombres de los campos de la tabla, pero no esincorrecto. Si cuando realizamos una inserción ésta afecta a todos los campos de la tabla no es necesario queindiquemos los nombre de los mismos, solamente es necesario cuando vayamos a realizar inserciones en lasque algunos campos del nuevo registro no vayamos a rellenarlos, es este caso esos campos en blancoquedarán definidos con el valor NULL. Aquí hay que hacer una pequeña llamada de atención. Podemosperfectamente hacer inserciones que solamente afectan a un subconjunto de los campos de un registro y elresto dejarlo en blanco, pero tenemos que tener la precaución de nunca dejar en blanco ningún campo quehayamos definido como NOT NULL, nos daría un error y no realizaría la inserción.

/* Actualiza la dirección y el CP del cliente con DNI 21547789 */Update Clientes set Direccion=”Plaza Mayor”, CP=”66789” where DNI=”21547789”

/*Borra el cliente con DNI 12456445 */Delete from Clientes where DNI=”12456445”

/* Borra todos los clientes de los que no tengamos nombre */ Delete from Clientes where Nombre is NULL

Como podemos apreciar en los ejemplo de los borrados y actualizaciones, utilizar estos procedimientos notiene, al igual que las inserciones, una gran complicación. El pequeño problema, en los dos primeros, estribaen la cláusula WHERE. Los ejemplos mostrados nos enseñan como utilizar WHERE en sus posibilidadesmás sencillas, obviamente, podríamos generar condiciones de borrado y actualización algo más complejas.Dejo para el artículo del próximo número de la revista Síntesis el abordar casuísticas más complejas de lacláusula, donde conoceremos con detalle toda su potencia. No obstante voy a citar, junto con algún ejemplomás, algunos de los operadores que podemos utilizar en ella:

• AND Es el “y” lógico.

• OR Es el “o” lógico.

• NOT Es el negador lógico.

• <, >, <=, >=, =, <> Son los comparadores.

• BETWEEN Especifica un intervalo de valores.

• LIKE Compara con un modelo. Ver tabla apartado Creación de reglas para datos.

Page 11: SQL y Firebird

• IN Compara con una lista de datos.

/* Borra todas las facturas emitidas antes del 1/1/2000 */Delete from Facturas where fecha < “1/1/2000”

/* Actualiza el valor del descuento al 25% a todos los clientes cuya última compra estéentre 200000 y 300000 pesetas */Update Cliente set descuento=25 where total_ultima_compra between 200000 and 300000

/* Borra todos los articulos cuyo código comienza por 210 */Delete from Articulos where codigo like “210%”

Modificar y borrar una tabla (ALTER TABLE, DROP TABLE)

Si necesitamos borrar una tabla, situación que se da en raras ocasiones, el comando es:

DROP TABLE nombre_tabla

Con todo el trabajo que lleva crear una tabla y lo fácil que es borrarla. Hay que llevar cierta precauciónsi la tabla se encuentra relacionada con otras tablas.

Y ahora, después del tremendo esfuerzo que nos ha supuesto conocer la sintaxis para el borrado de latabla, je, je, vamos a continuar con nuestra línea normal, ALTER TABLE.

ALTER TABLE, a nadie se le escapa, sirve para realizar modificaciones de definición sobre las tablasya generadas, modificaciones añadiendo o eliminando campos o claves. Su sintaxis:

ALTER TABLE tabla {ADD {COLUMN tipo de campo[(tamaño)][CONSTRAINT indice]CONSTRAINT indice multicampo} |DROP {COLUMN campo CONSTRAINT nombre del indice} }

Ya lo sé, un poquito liado ¿verdad?, venga, vamos a ver unos ejemplos:

/* Agrega un campo Comentario a la tabla Clientes */Alter table Clientes add column Comentario varchar(255)

/* Elimina el campo IVA de la tabla Articulos */Alter table Articulos drop column IVA

/* Añade un campo CIF a la tabla Articulos y después lo convierte en clave ajena pararelacionar cada artículo con el proveedor que lo suministra. El CIF es el identificador deun proveedor */Alter table Articulos add column CIF char(9)Alter table Articulos add constraint caj_Articulos foreing key (CIF) references Proveedores

/* Aunque no tenga sentido, borraremos la clave ajena de la tabla LineasFactura a la tablaFactura */Alter table LineasFactura drop constraint caj_LineasFactura1

En el apartado donde he explicado como se crean las tablas he comentado que cuando generamos unaclave, bien sea ajena, primaria o alternativa, el comando CONSTRAINT no es obligatorio incluirlo aunque sirecomendable, ahora podemos darnos cuenta del por qué. Si no utilizamos CONSTRAINT no podremosponer un nombre a la nueva clave generada, si la clave no dispone de nombre después no podremos tratarlacon otros comandos como son los vistos en este apartado. No cuesta nada, al generar las claves, otorgarlesun nombre, y podemos evitar problemas más adelante.

Page 12: SQL y Firebird

Creación y eliminación de reglas para los datos (CREATE RULE,SP_BINDRULE, DROP RULE, SP_UNBINDRULE)

Las reglas nos van a permitir tener un control sobre los datos que se insertan en nuestras tablas, sonreglas de validación de datos. A través de una regla, vamos a definir una serie de condiciones, o podemos vertambién como asignar un formato a los datos de los campos. Cuando realicemos una inserción en un registro,ésta se llevará a termino solamente si los datos cumplen las condiciones, o tienen el formato, que hemosimpuesto en la regla.

Las reglas que generemos se asociarán a campos de nuestras tablas. No podemos asociar una regla auna tabla completa, solamente a uno de sus campos.

El comando para crear reglas es CREATE RULE, y su sintaxis es muy sencilla:

CREATE RULE nombre_regla AS @variable LIKE expresion1[OR @variable LIKE expresion2

... OR @variable LIKE expresionN]

Una vez que hemos creado nuestra regla tendremos que hacerle saber al sistema a qué campo de quétabla tiene que ir asociada, es decir, tenemos que indicar qué datos concretos tiene que controlar. Lavinculación de una regla a un campo concreto de nuestra base de datos se realiza con el comandoSP_BINDRULE, y es así de fácil:

EXEC SP_BINDRULE nombre_regla, 'tabla.campo'

El parámetro expresion del comando LIKE define el dominio correcto de los datos, es decir, define laforma o regla que tienen que cumplir los datos para poder ser aceptados y por lo tanto introducidos en elcampo. A continuación vamos a ver de que símbolos disponemos para crear dicha expresión:

• % Cualquier cadena de 0 o más caracteres.

• _ (subrayado) Cualquier carácter individual.

• [ ] Carácter individual dentro de un conjunto o intervalo: [abcde], [a-e]

• [ ^ ] Negación

Vamos a despejar las nubes de nuestras mentes, ¿cómo?, pues como siempre, con unos ejemplitos.

Imaginemos una tabla de asignaturas donde tenemos todas las asignaturas que se imparten en un colegio.En la tabla tendremos un campo dia que indica el día que esa asignatura es impartida. Las asignaturassolamente se imparten de lunes a viernes, situación que tendremos que controlar a la hora de introducir losdatos de las asignaturas en la tabla. Una forma de controlarlo sería perfectamente con una regla.

create rule dias_lectivos as @dia like 'lunes'or @dia like 'martes'or @dia like 'miercoles'or @dia like 'jueves'or @dia like 'viernes'

exec sp_bindrule dias_lectivos, 'asignaturas.dia'

Imaginemos una tabla Articulos de una tienda de muebles que sólo comercializa muebles de madera,concretamente sólo de roble, cerezo y haya.

create rule tipo_madera as @madera like'roble'or @dia like 'cerezo'or @dia like 'haya'

exec sp_bindrule tipo_madera, 'articulos.material'

Page 13: SQL y Firebird

Imaginemos una tabla Articulos de una fábrica de componentes electrónicos donde el código de losnuevos artículos debe tener siempre el mismo formato, comenzar por la letra H, después una letra y porúltimo tres números.

create rule restriccion_codigo as @codigo like 'H[A-Z]7[0-9][0-9][0-9]'

sp_bindrule restriccion_codigo, 'articulos.codigo'

Si necesitamos borrar una regla creada, el comando es DROP RULE, pero antes de borrarla, si ya lahabíamos vinculado a algún campo, tendremos que desvincular la regla del campo al que esté vinculada. Elcomando para desvincular reglas es SP_UNBINDRULE. Si no desvinculamos antes de borrar la regla, seproducirá un error y no la podremos borrar. La sintaxis de estos comandos es:

EXEC SP_UNBINDRULE 'tabla.campo'

DROP RULE nombre_regla

Una vez desvinculado el campo de su regla podremos vincularle otra regla diferente.

Creación y eliminación de tipos definidos por el usuario(SP_ADDTYPE, SP_DROPTYPE)

Como usuarios podemos crearnos nuestros propios tipos de datos. La principalutilidad de esta posiblidaden estos momentos para nosotros será ahorrarnos trabajo. Si vamos a tener en nuestra base de datos envarias tablas un campo que va a ser del mismo tipo, al cual vamos a tener que asociarle una regla, es siempremás cómodo crearnos un tipo de dato para él y asociarle una regla a ese tipo de dato, el cual, cada vez que loutilizamos para definir un campo cualquiera de nuestras tablas, este campo ya tendrá asociada la regla. Si noobramos así, tendríamos que definirnos el campo en cada una de las tablas con un tipo de dato simple y luegoa cada campo tener que ir asociándole por separado la regla, es una solución mucho más laboriosa que laprimera.

Definiendo un tipo de dato, o definiendo un tipo de dato y vinculándole una regla, ahorramos tiempo yesfuerzo, porque solamente el trabajo lo tendremos que realizar una vez, ya que al asociar a diferentescampos de diferentes tablas el tipo de dato generado, estos campos ya estarán perfectamente definidos, conregla incluida. Sin embargo, si no lo hacemos así, tendremos que repetir el mismo proceso tantas veces comoel campo aparezca en nuestra base de datos.

Para definir o generar, un tipo de dato por el usuario el comando es ADD_TYPE:

SP_ADDTYPE nombre_tipo_dato_usuario, 'tipo_dato_simple'

Para vincular una regla con un tipo de dato de usuario, el comando también es SP_BINDRULE, comohemos visto en el apartado anterior, pero con una pequeñísima diferencia sintáctica, las comillas:

EXEC SP_BINDRULE nombre_regla, tipo_dato_usuario

Para desvincular un tipo de dato de usuario de su regla asociada, el comando, al igual que ocurre con lavinculación, es el mismo que para desvincular una regla de un campo de una tabla, y también sufre la mismavariación que el comando de vinculación. El comando es SP_UNBINDRULE, y su sintaxis:

EXEC SP_UNBINDRULE tipo_dato_usuario

Veamos un ejemplo. Si en nuestra base de datos vamos a tener un campo teléfono varias veces repetido,una vez en la tabla de clientes, otra en la de proveedores, otra en la de colaboradores y otra vez más en la desubcontratados, y siempre este campo va a tener el mismo formato, nueve números, la mejor opción seríadefinirlo como tipo de usuario y asignarle una regla. De forma que cuando en cada una de las tablasgeneremos el campo teléfono, le asignemos este tipo de dato donde ya tenemos incorporado el formato y laregla de validación. La secuencias de instrucciones sería:

Page 14: SQL y Firebird

sp_addtype tipo_telefono, 'char(9)'

create rule telefono_correcto as @telefono like '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'

exec sp_bindrule telefono_correcto, tipo_telefono

create table clientes(

...telefono tipo_telefono,...

)

Si queremos borrar el tipo de dato definido por el usuario, SP_DROPTYPE. Pero si tiene una reglavinculada antes tendremos que romper el enlace que les une. Sería conveniente que si la regla no la vamos aasignar a otro tipo de dato o a otro campo de alguna tabla, borrar la regla.

Partiendo del ejemplo del número de teléfono vamos a borrar el tipo de dato. Como está vinculado a unaregla, antes tendremos que desvincular y además, como la regla ya no tiene sentido la borraremos también.

Exec sp_unbindrule tipo_telefono

drop rule telefono_correcto

sp_droptype tipo_telefono

El borrar un tipo de dato de usuario no es una acción que se suela realizar, a no ser que inmediatamentedespués de haberlo creado nos demos cuenta que está mal definido, o si el campo o campos de las tablaspara los que se definió el tipo de datos los eliminamos de sus tablas correspondientes.

Creación y borrado de valores por defecto (CREATE DEFAULT,SP_BINDEFAULT, DROP DEFAULT, SP_UNBINDEFAULT)

Un valor por defecto es un valor que se le asigna a un campo de la tabla mientras haya ausencia de otrovalor introducido por el usuario. Las instancias del campo tendrán por valor su valor por defecto si éste no secambia. Cuando un campo, en la mayoría de las ocasiones, va a tener siempre un valor concreto, este valorse le puede asignar por defecto, de forma que a no ser que a la hora de la inserción de un nuevo registro o desu actualización lo cambiemos, siempre permanecerá con él.

Los pasos para crear un valor por defecto son: primero crear el valor por defecto, CREATEDEFAULT, y segundo vincular este valor por defecto, o a un campo determinado de una tabla o a un tipo dedato definido por el usuario. Para vincular, el comando es SP_BINDEFAULT, y la sintaxis de los comandoses:

CREATE DEFAULT nombre_valor as valor

EXEC SP_BINDEFAULT 'nombre_valor, 'tabla.campo' /* Para campo concretos de tablas */

EXEC SP_BINDEFAULT nombre_valor, tipo_dato_usuario /* Para tipos de datos de usuarios */

Un ejemplo. En una tabla de datos de trabajadores de una empresa donde se reflejan sus datos laboralesmensuales, tenemos un campo horas_trabajadas, que refleja las horas trabajadas por casa empleado almes. A no ser que el empleado falte por algún motivo injustificado al trabajo, sus horas trabajadas mensualesson siempre las mismas, supongamos 120. Podríamos aplicarle a este campo un valor por defecto que nosevite para cada trabajador tener que estar siempre introduciendo este valor. Solamente tendremos quecambiar el valor cuando el trabajador no se ajuste a las horas normales de trabajo.

create default horas_trabajadas_120 as 120

Page 15: SQL y Firebird

exec sp_bindefault 'horas_trabajadas_120', 'trabajo_mes.horas_trabajadas'

Los valores por defecto definidos se puede borrar con el comando DROP_DEFAULT, pero si lostenemos ya vinculados previamente tendremos que romper el enlace con SP_UNBINDEFAULT. ¿Lasintaxis?, enseguida:

DROP DEFAULT nombre_valor

SP_UNBINDEFAULT 'tabla.campo' /* Para campos concretos de tablas */

SP_UNBINDEFAULT tipo_dato_usuario /* Para tipos de datos definidos por el usuario */

Si deseáramos borrar el valor por defecto utilizado en el ejemplo anterior, primero, a nadie se le escapaya, tendríamos que desvincularlo del campo o del tipo de dato de usuario y después proceder a su eliminación.Veamos la secuencia de instrucciones:

sp_unbindefault 'trabajo_mes.horas_trabajadas'

drop default horas_trabajadas_120

Breve anticipo del siguiente artículo. Las consultas con SQL, demomento...

Bueno, ya hemos llegado casi al final. A lo largo de todo el artículo hemos conocido los fundamentos deSQL, un lenguaje soportado por todos los grandes gestores de bases de datos, que nos permite trabajar connuestros datos con una independencia del gestor. SQL día a día se instaura más en el mercado con lo que sehace ya imposible pensar en trabajar con bases de datos sin pensar en SQL.

Hasta aquí hemos conocido como podemos definir nuestros datos, en el próximo artículo, dentro de dosmeses, veremos como podemos trabajar con ellos. Como se que la espera es larga voy a iniciar un poco lostemas que podremos conocer , espero que antes que podamos darnos cuenta, en lo que será una continuaciónde hasta lo aquí expuesto.

No sirve de nada que diseñemos nuestra base de datos, sus tablas, sus reglas, nuestros propios tipos dedatos, introduzcamos datos, etc..., si después no vamos a manipularlos, a darles vueltas, a jugar con ellos. Unode los comandos que SQL nos ofrece para divertirnos con nuestros datos es SELECT, de hecho, es uno delos más conocidos de todo el lenguaje.

No vamos a detallar en este momento como utilizar SELECT solamente pondremos su sintaxis mássencilla y mostraré algunos ejemplos de utilización.

SELECT campo1[, campo2, ... ,campoN]FROM tabla1 [, tabla2, ... ,tablaN][ WHERE condicion1

[AND condicion2 | OR condicion2 | ... | AND condicionN | OR condicionN] ]

Traducido a un lenguaje natural podríamos interpretar la sintaxis anterior como: selecciona estos camposque se encuentran en estas tablas si cumplen estas condiciones. Esta sería una forma muy llana de interpretarel comando SELECT, y muy poco ortodoxa, pero sencilla para el que nunca haya visto antes el comando.

Vamos a poner un cuantos ejemplos, antes de verlos recomiendo que se recuerde el apartado inserciónmodificación y borrado de datos, de este mismo artículo, donde explicamos, a grandes rasgos, elfuncionamiento de la WHERE.

/* Tenemos una tabla Artículos y queremos ver todos sus datos */

Page 16: SQL y Firebird

select * from Articulos

/*De la tabla Artículos sólo queremos ver los datos de los campos Código y Nombre delartículo */

select Codigo, Nombre from Articulos

/* El mismo caso que el anterior pero de los artículos cuyo precio de venta sea mayor que1000 pesetas */

select Codigo, Nombre, PrecioVenta from Articuloswhere PrecioVenta > 1000

/* El mismo caso que el anterior pero los artículos que tengan un precio de ventacomprendido entre 1000 y 3000 pesetas */select Codigo, Nombre, PrecioVentafrom Articuloswhere PrecioVenta between 1000 and 3000

/* Todos los clientes que residan en la ciudad de Alicante */select *from Clienteswhere Ciudad=”Alicante”

/* Todos los artículos cuya materia prima sea el acero o el aluminio */select Nombrefrom Articuloswhere materia=”aluminio” or materia=”acero”

Y así podríamos continuar en innumerables ejemplos hasta llegar a determinar toda la potencia deSELECT.

Ha llegado ya el momento de despedirnos, espero haber ayudado a que conozca mejor SQL, y a que seinterese, si no lo estaba ya, por este mundo de las bases de datos. Le emplazo para los siguientes números dela revista Síntesis donde continuaré buceando por este océano tan grande, el Océano Bases de datos, paraintentar que usted, desde mí pequeña contribución, siempre se mantenga a flote en él y sin perder el rumbo.

Un saludo, muchas gracias y hasta pronto.

Page 17: SQL y Firebird

Manipulación de datos en SQL. Las Consultas.Óscar Javier Segura Amorós - [email protected]

Las consultas de SQL con su archiconocidoSELECT, de ahora en adelante, uno de nuestros

mejores amigos.

Hola de nuevo. Continua aquí la serie sobre el lenguaje SQL que comenzó en el número anterior de larevista. Lo primero de todo y antes de proseguir, vamos a hacer un poco de memoria para recordar las basesque ya quedaron sentadas en el artículo anterior y que nos van a servir de punto de partida en éste.

En el anterior artículo comenzamos viendo que es SQL (Lenguaje de Consultas Estándar), vimos que eraun lenguaje para trabajar con las bases de datos, que era un lenguaje muy difundido por su altaestandarización y que prácticamente la totalidad de los sistemas gestores de bases de datos lo trabajaban y enmuchas ocasiones, sin diferencias notables en su forma. Vimos que tiene dos ámbitos de trabajo, puespodemos clasificar todas sus instrucciones dentro de dos grandes grupos: las instrucciones que trabajan con laestructura de los datos, o lenguaje de definición de datos (LDD) y las instrucciones que trabajan con los datosen sí, o lenguaje de manipulación de datos (LMD). En el pasa artículo nos centramos solamente en ellenguaje de definición de datos, momento en el cual abordamos las instrucciones más importante dentro delgrupo de definición de datos, como las instrucciones para crear las tablas, las reglas, los tipos de datos,insertar valores, borrarlos, modificarlos,..., prometiendo una continuación al emplazaros a todos para lasiguiente entrega donde abordaría las instrucciones de manipulación de datos, y como lo prometido es deuda,aquí estoy de nuevo.

En el artículo de este número vamos a empezar a conocer las instrucciones de manipulación de datos.Estas son muchas y variadas por lo que, de momento, no las vamos a tratar en su totalidad. Vamos aempezar por el principio, centrándonos en las consultas bajo SQL dejando ya para el próximo artículo lasvistas y los procedimientos almacenados. Sería un disparate, por su complejidad y extensión, pretenderconocer todo el lenguaje de manipulación de datos en solamente un artículo. De esta forma, vamos a podercentrarnos en algo más concreto, las consultas, verlas con profundidad y descubrir toda la potencia que nosofrecen.

Bueno, si nos vamos a centrar en las consultas, lo primero que nos tendremos que plantear es, ¿qué esuna consulta?, ¿para qué sirve?. Preguntas totalmente fuera de lugar puesto que todos ya sabemos a estasaltura que las consultas son unos procedimientos que nos van a permitir interrogar a nuestra base de datoslanzando preguntas a las tablas para obtener de esta forma los datos que nosotros necesitamos en unmomento determinado. De nada sirve introducir datos en unas distribuciones de tablas si después no podemosrecuperarlos, es más, ya no basta recuperar esos datos, sino que además queremos recuperar no la totalidadde los datos, solamente vamos a querer recuperar en cada momento los datos que no son necesarios. Paraeso existen los criterios de búsqueda de datos dentro de las consultas.

La complejidad de las consultas estriba, no en hacer la consulta en si, puesto que una consulta que nosmuestre todos los datos de una tabla o de un conjunto de ellas no tiene ningún misterio. Muchas veces lacomplejidad la vamos a encontrar en generar esos criterios, esas condiciones que van a tener que satisfacerlos datos que la consulta nos va a mostrar, los datos que nosotros queremos conocer de entre todos los quetenemos almacenados.

Y ya sin más dilación empecemos que tenemos mucho camino por recorrer, suerte en el recorrido.

Page 18: SQL y Firebird

Base de datos de ejemplo. Gestión de proveedores.

Junto con el artículo encontrareis varios ficheros para descargar. Estos ficheros son un apoyo, uncomplemento para poder entender mejor los diferentes apartados que a continuación abordaremos.

Durante todo el artículo completaré las explicaciones de cada apartado con ejemplos. Estos ejemplosestán realizados sobre una base de datos, Gestión de proveedores, la cual podría ser un pequeño ejemplode control de artículos de una empresa informática.

En los ficheros encontrareis el scrip de SQL para generar la base de datos e introducir en ella unosdatos, que por supuesto son imaginarios, datos suficientes para poder trabajar cómodamente. Ademásencontrareis otros ficheros con propuestas de ejercicios y sus soluciones, basados también en la en Gestiónde proveedores, que servirán para poder practicar todos los apartados vistos en el artículo.

Los ficheros son 3, los cuales os describo a continuación:

? Fichero BaseDatos.sql: Dentro de este fichero encontrareis el scrip de SQL para lacreación de la base de datos de Gestión de proveedores junto con las instrucciones deinserción de los datos para que se pueda trabajar ya con ella. El scrip está optimizado parautilizarlo en SQL Server 7, lo cual no quiere decir que no vaya a funcionar en otrosgestores. Si lo queremos utilizar en Interbase tendríamos que hacer dos pequeñasmodificaciones: en la creación de las tablas sustituir el tipo de datos para fechas, datetime,por el tipo soportado por Interbase, date, y en las inserciones de los datos, las fechas queestán escritas en el formato dd/mm/aaaa cambiarlas por el formato mm/dd/aaaa. Trasestas dos modificaciones podríamos correr el scrip en Interbase sin ningún problema.

? Fichero Ejercicios.txt: Donde encontrareis los enunciados de propuestas de ejerciciospara poder practicar todo lo aprendido. Los ejercicios están basados en la base de datosde Gestión de proveedores.

? Fichero Soluciones.sql: Donde encontrareis las soluciones a los ejercicios propuestos enel fichero Ejercicios.txt en forma de scrip de SQL.

Os presento ahora las tablas de la base de datos de ejemplo Gestión de proveedores:

VENDEDOR(

numvend SMALLINT not null, nomvend VARCHAR(30), nombrecomer VARCHAR(30), telefono VARCHAR(15),calle VARCHAR(30), ciudad VARCHAR(20), provincia VARCHAR(20), cod_postal CHAR(5)

)Clave primaria: (numvend)

PIEZA(

numpieza VARCHAR(16) not null, nompieza VARCHAR(30), preciovent INTEGER)

Clave primaria: (numpieza)

PRECIOSUM(

numpieza VARCHAR(16) not null, numvend SMALLINT not null, preciounit INTEGER, diassum SMALLINT, descuento SMALLINT

)Clave primaria: (numpieza,numvend)Clave ajena: (numpieza)--> PIEZAClave ajena: (numvend)--> VENDEDOR

Page 19: SQL y Firebird

PEDIDO(

numpedido SMALLINT not null, numvend SMALLINT, fecha datetime)

Clave primaria: (numpedido)Clave ajena: (numvend)--> VENDEDOR

LINPED(

numpedido SMALLINT not null, numlinea SMALLINT not null, numpieza VARCHAR(16), preciocompra INTEGER, cantpedida SMALLINT, fecharecep datetime, cantrecibida SMALLINT

)Clave primaria: (numpedido,numlinea)Clave ajena: (numpedido)--> PEDIDOClave ajena: (numpieza)--> PIEZA

INVENTARIO(

numbin SMALLINT not null, numpieza VARCHAR(16) not null, cantdisponible SMALLINT, fecharecuento datetime, periodorecuen SMALLINT, cantajuste SMALLINT, cantreord SMALLINT, puntoreord SMALLINT

)Clave primaria: (numbin)Clave alternativa: (numpieza)

Clave ajena: (numpieza)--> PIEZA

Es una ventaja, si antes de realizar los ejercicios y tras crear la base de datos e insertar los datos,listamos los datos de cada una de las tablas por impresora. De esta forma al tener un listado de cada una deellas podemos comprobar sobre el papel si los datos obtenidos con la ejecución de nuestras consultas son losdatos correctos o la consulta es incompleta o errónea. ¿Qué como podemos hacer eso?, muy fácil, veamos elsiguiente apartado.

No perder de vista el esquema de las tablas que se han presentado, puesto que entenderemos mejor lasexplicaciones de los apartados.

Selección de columnas en consultas de una sola tabla (SELECT,FROM)

En las consultas, la selección de las columnas que vamos a mostrar se realiza con las cláusulasSELECT, para indicar las columnas a mostrar y FROM para indicar la tabla en la que se encuentran dichascolumnas. Su sintaxis:

SELECT [DISTINCT] Columna1,...,ColumnaNFROM Tabla

La sintaxis descrita, la cual es muy simple, serviría solamente para mostrar las columnas de una únicatabla, puesto que en la cláusula FROM solamente hemos especificado una tabla. En siguientes apartadosveremos como realizar consultas en las que se utilizan varias tablas, no basta con indicar las diferentes tablasen la cláusula FROM.

Si queremos mostrar la totalidad de las columnas de una tabla no es necesario enumerarlas todas dentrode la cláusula SELECT, bastaría con porner un *, indicativo de totalidad.

En el apartado anterior recomendaba que se listaran todos los datos de cada una de las tablas. Siqueremos mostrar toda la tabla Vendedor, podríamos comenzar por ella misma, es decir, todos sus datos,todas sus columnas:

select *

Page 20: SQL y Firebird

from vendedor

Al poner un * nos ahorramos el tener que escribir el nombre de todos sus campos. Esta consulta latendríamos que repetir para cada una de las seis tablas.

Si ahora quisiéramos ver solamente los datos correspondientes al numero de vendedor y su nombre, sinquerer mostrar la información del resto de las columnas, tendremos que seleccionar exclusivamente estoscampos. Recordar que aunque la tabla seleccionada tenga más campos, solamente se mostrarán aquellos queindiquemos, seleccionemos en la cláusula SELECT:

select numvend, nomvendfrom vendedor

Si lo deseamos, podemos dar un nombre a las columnas que mostramos en la consulta. Para renombralasbastará con escribir el nombre que les queramos dar, entre comillas si es un nombre compuesto o si es unnombre simple directamente, después del nombre real de la columna en la sentencia SELECT. Si no lohacemos el gestor nos mostrará el nombre real de las columnas. Interbase no soporta los renombramientoscompuestos de columnas.

select numvend “Número de vendedor”, nomvend “Nombre del vendedor”from vendedor

Cuando renombramos las columnas, indicar, que el nuevo nombre pertenece solamente al ámbito de laconsulta, por lo que nunca se cambiará el nombre real de la columna dentro la de base de datos, es lo lógico.Sería un auténtico galimatías si cada vez que renombramos una columna en una consulta ese nuevo nombretambién se extendiera a las correspondientes tablas.

El parámetro DISTINCT se utiliza cuando en los datos obtenidos en la consulta tenemos algunas filasque son iguales, con este parámetro eliminaremos de la consulta aquellas filas que sean repetidas.

select distinct provinciafrom vendedor

Como existen varios vendedores que pertenecen a las mismas provincias, al ejecutar esta consultaobtendríamos la provincia de cada uno de los vendedores por lo que tendríamos muchos nombres deprovincias que se repiten. Para evitarlo indicamos a la consulta que solamente nos muestre aquellas filas quesean diferentes, eliminando así del resultado las que repiten.

Ordenar resultados de la consulta (ORDER BY)

Podemos realizar ordenaciones de los resultados que las consultas nos van a devolver. Podemos elegirque los resultados obtenidos se muestren de forma ascendente o descendente, basándose en los valores deunas determinadas columnas de la consulta. Esto lo conseguimos con la instrucción ORDER BY.

ORDER BY Columna1,...,ColumnaN [ASC|DESC]

ORDER BY lo situaremos siempre por debajo de la cláusula FROM, esto no quiere decir que deba irexactamente bajo esta cláusula, puesto que en los siguientes apartados veremos otras instrucciones quepodemos utilizar, la única condición es que ORDER BY nunca se situe antes que SELECT o FROM.

La columnas indican los campos que nos van a servir como criterios de ordenación, de forma que siindicamos varias columnas siempre se ordenarán los valores en función de la primera, y si en la primera seencuentran valores iguales, entonces las filas correspondientes a estos valores se ordenarán según la segundacolumna indicada, y así sucesivamente.

ASC y DESC que son dos parámetros opcionales, se utilizan para indicar la ordenación, si deseamos unaordenación ascendente o descendente respectivamente. En el caso que se se indique ninguno de los dosparámetros se realizará una ordenación ascendente.

Page 21: SQL y Firebird

Si no especificamos nosotros en la consulta ningún orden de listado, los datos serán mostrados en elorden en el que se encuentran en las tablas.

Un ejemplo. Mostrar de todos los vendedores su nombre, dirección y número de vendedor de formaordenada.

select nomvend “nombre”, direccion, numvend “número vendedor”from vendedororder by nomvend

Condición de selección (WHERE)

En la mayoría de nuestras consultas no querremos hacer listados de la totalidad de los datos de una tabla,sino que querremos hacer listado parciales según algún criterio de selección de datos, es decir, mostrarsolamente aquellos datos que cumplan unas determinadas condiciones, unos determinados criterios. Paraimponer estos criterios de selección se utiliza la cláusula WHERE y su sintaxis es:

WHERE Condición [and Condición2 | or Condición2 | ... | and CondiciónN | or CondiciónN]

En una cláusula WHERE podemos poner tantos criterios de selección como necesitemos, uniendo dichoscriterios por los los operadores lógicos AND y OR.

Los criterios o condiciones se pueden especificar de muchas formas, de momento vamos a versolamente la forma más simple, los comparadores : <, >, <=, <=, =, <>, !=, !<, !>. En siguientes apartadosutilizaremos cláusulas que nos van a permitir simplificar las condiciones o darles mayor potencia.

Y como no hay nada mejor que un ejemplo... Antes hemos listado todo el contenido de la tabla vendedor,ahora solamente vamos a querer listar a aquellos vendedores cuya ciudad sea Alicante:

select *from vendedorwhere ciudad=”Alicante”

Como la ciudad es un campo de tipo carácter siempre que queramos trabajar con él tenemos que hacerloponiendo el dato entre comillas dobles.

Queremos los vendedores de que pertenezcan a la empresa OLE ESPAÑA y sean de la ciudad deMadrid:

select * from vendedorwhere nombrecomer=”ole españa” and ciudad=”madrid”

Y ahora queremos los número de pieza y la fecha de recuento de todas aquellas piezas de las quetengamos una cantidad disponible superior o igual a 10 unidades:

select numpieza,fecharecuentofrom inventariowhhere cantdisponible>=10

Llegados a este punto un comentario sobre diferencias de funcionamiento de un gestor de bases de datosa otro. Los ejemplos ahora citados funcionan perfectamente en SQL Server, mientras que si los intentamosutilizar bajo Interbase hay que tener una pequeña precaución, puesto que éste hace distinción entremayúsculas y minúsculas en los datos, así que tendremos que tener la precaución de trabajar siempre ennuestra base de datos en un solo formato, o bien mayúsculas o minúsculas. Si el primer ejemplo de todos loejecutamos bajo Interbase la consulta no nos hubiera devuelto ningún dato, siendo esto incorrecto, al sí haberdatos que cumplen el criterio, pero no se muestran porque nosotros no hemos puesto el término de condiciónen mayúsculas, tal y como se encuentra el dato almacenado en la tabla.

Page 22: SQL y Firebird

Consultas con varias tablas

Cuando realizamos consultas en las que vamos a utilizar varias tablas, dos, tres, cuatro, ..., normalmenteesas tablas son tablas relacionadas, es decir, unas tablas hacen referencias a las otras a través de las clavesajenas que hayamos definido en la creación de las mismas. En pocas ocasiones vamos, en una mismaconsulta, a visualizar datos de varias tablas que no están relacionadas.

La forma de realizar una consulta utilizando varias tablas es muy sencilla, basta con poner los nombre delas tablas, separadas por comas, en la cláusula FROM.

FROM Tabla1,...,TablaN

Poner los nombre de las tablas a utilizar dentro de la cláusula FROM sería suficiente si las tablas fuerantablas no relacionadas, es decir, si fuera una de esas consultas que en raras ocasiones se nos va a presentarrealizar. Si las tablas están relacionadas, deberemos dentro de la cláusula WHERE indicarlo. La forma deindicarlo es igualando los campos que tienen en común cada tabla con las demás.

FROM Tabla1, Tabla2WHERE Tabla1.CampoComun=Tabla2.CampoComun

Veámoslo con un ejemplo. Queremos obtener todas los números de pieza y en que número de pedido sehan solicitado siendo el número de vendedor el 1. ¡Qué nadie se asuste!, parece más de lo que en realidad es.¿La solución?, sí, claro, al instante:

select linped.numpedido "Numero pedido",numpieza "Numero de pieza"from linped,pedido where numvend=1 and linped.numpedido=pedido.numpedido

Necesitamos la tabla Pedido puesto que en ella se encuentra el número de vendedor al que se realiza elpedido y necesitamos también la tabla Linped (Linea de pedido) puesto que en ella se encuentran las piezasque se piden en cada pedido. Estas dos tablas están relacionadas por el dato Numpedido (Número de pedido),que si repasamos el esquema de las tablas, es la clave ajena que existe de Linped a Pedido, y este enlace selo indicamos a la consulta en el apartado del WHERE, además también dentro de éste apartado indicamos elcriterio de que el vendedor tiene que ser el número 1. Incluso para que queden más claros los datosmostrados, renombramos las columnas.

En el ejemplo anterior apreciamos como el dato común en las dos tablas y que sirve de enlace entre ellases Numperido, y cada vez que hacemos referencia a él tenemos que indicar a que Numpedido nos estamosrefiriendo, si al de la tabla Linped o al de la tabla Pedido. Esto lo realizamos escribiendo el nombre de la tabla,un punto y el nombre del campo duplicado, por así llamarlo. Por ese motivo en la cláusula SELECT, cuandoutilizamos Numpedido le tenemos que anteponer la tabla a la que pertenece. En el caso del SELECT, la tablaa la que pertenece Numpedido es indiferente, puesto que ya en el WHERE nos hemos ocupado de igualaresos números de pedido. Sin embargo no ocurre así en el WHERE, donde si tenemos que hacer correspondercada número de pedido de la igualdad con su tabla, por un lado el Numpedido de la tabla Linped y por el otroel Numpedido de la tabla Pedido.

Si no realizamos el enlace entre las tablas dentro de la consulta se produciría un producto cartesianoentre los datos de ambas tablas, relacionando así cada dato de la primera tabla con todos los datos de lasegunda y por lo tanto mostrándonos un conjunto de datos que no son reales. Recomiendo que pruebes arepetir la consulta anterior suprimiendo el enlace de las tablas y observes el resultado.

Es recomendable, para optimizar la consulta, indicar siempre el enlace de las tablas como últimacondición en el WHERE. Cuando nosotros dentro del apartado FROM indicamos que queremos trabajar convarias tablas, el gestor crea una tabla virtual, dentro del ámbito de la consulta, en la que introduce el resultadode realizar el producto cartesiano entre las tablas que nosotros le hemos indicado. Después sobre esta tablavirtual elimina las filas, los registros, que no cumplan los criterios indicados en el WHERE. Va evaluandosobre los datos de la tabla virtual los criterios por el orden en el que se encuentran escritos, de esta forma sinosotros antes de especificar el enlace hemos especifica el resto de criterios, a la hora de comprobarlos

Page 23: SQL y Firebird

tendrá que operar con menos datos puesto que muchos de ellos ya los habrá eliminado porque no cumplían lascondiciones anteriores. Entendamos que al comprobar el enlace tiene que recorrer todos los registros de latabla comprobando la igualdad de cada registro con todos los demás, trabajo muy arduo, ayudémosle a que lascomprobación sea lo más pequeña posible. Tras comprobar todos los datos con los criterios impuestos y losenlaces, los datos que hayan superado todas las condiciones serán los que queden en la tabla virtual, y estános será presentada a nosotros como resultado de la consulta.

Rangos de valores (BETWEEN)

En las consultas, la búsqueda de valores entre unos rangos determinados resulta de gran importancia.Podríamos hacerlas utilizando los operadores de comparación, pero existe una forma mejor, la instrucciónBETWEEN.

WHERE Columna [NOT] BETWEEN Expresión1 AND Expresión2

La Columna será la columna dentro de la cual queramos comprobar si existe el valor comprendido dentrodel rango que nosotros marcamos. La Expresión1 y Expresión2 será el menor valor del rango y el mayorvalor del rango respectivamente. Los rangos de valores deben de ser numéricos o fechas. Fijémonos quepodemos realizar selecciones inversas al poder utilizar el operador NOT.

Si queremos encontrar todas aquellas piezas cuyo precio de venta esté comprendido entre 500 ptas y2000 ptas. Tenemos dos formas de hacerlo, la primera, que es la más larga y la segunda que es la másadecuada:

/*Primera forma. Para principiantes. No es su caso*/select *from piezawhere preciovent>=500 and preciovent<=2000

/*Segunda forma.*/select *from piezawhere preciovent between 500 and 2000

Si por el contrario, quisiéramos encontrar todas aquellas piezas cuyo precio de venta no estécomprendido entre 500 y 2000 ptas también tenemos dos formas de hacerlo:

/*La primera, que como antes no es la más correcta*/select *from piezawhere preciovent<=500 or preciovent>=2000

/*La segunda, la buena*/select *from piezawhere preciovent not between 500 and 2000

Page 24: SQL y Firebird

Búsqueda en listas de valores (IN)

Una lista es una sucesión de valores separados entre comas. La cláusula IN nos permite trabajar conuna lista de valores, para ello, la sintaxis sería la siguiente:

WHERE Columna [NOT] IN (lista de valores)

De esta forma podemos comparar los datos de una columna de una tabla con una lista de valores de unaforma muy sencilla, evitándonos el tener que comparar la columna con cada uno de los valores de formaindependiente y uniendo todas esas comparaciones con el operador OR.

La lista de valores puede ser de tres tipos: o una lista de valores numéricos, en cuyo caso irán separadospor comas, o una lista de valores alfanuméricos, o fechas, en cuyos casos, cadenas alfanuméricas o fechas,irán separados por comas y además cada uno de ellos encerrado entre comillas dobles o simples.

Listar todos las líneas de los pedidos 1,2 y 5.

select *from linpedwhere numpedido in (1,2,5)

Listar los nombres, números y cantidad disponible de todas aquellas piezas suministradas por vendedoresde las provincias de Alicante, Madrid o Valencia.

select nompieza "Nombre pieza",li.numpieza "Número pieza", cantdisponible "Cantidaddisponible", provincia "Provincia"from vendedor ve, pieza pie, inventario inv, pedido pe,linped li where provincia in ("Alicante","Madrid","Valencia") and ve.numvend=pe.numvend and pe.numpedido=li.numpedido and li.numpieza=pie.numpieza and pie.numpieza=inv.numpieza

Comentemos el ejemplo anterior que tiene mucha “miga”. Lo más complicado es la cantidad de enlacesque hemos tenido que hacer entre las diferentes tablas. Esta gran cantidad de enlaces es debido a que dos delos datos que queremos obtener están en una tabla, el tercero está en otra y la condición que se debe decumplir está en otra diferente, por eso tanta tabla y tanto enlace. Si nos fijamos en la cláusula FROM, trascada una de las tablas que queremos cargar hemos definido un alias, de forma que cuando queramos, en otroapartado de la consulta, hacer referencia a esa tabla lo podamos hacer de forma más cómoda utilizando elalias, es simplemente por comodidad. En la cláusula WHERE hemos puesto el criterio de la provincia loprimero de todo y después los enlaces, de esta forma optimizamos la ejecución de la consulta como ya heexplicado en apartados anteriores. En la cláusula SELECT hacemos referencia al campo Numpieza, campo ocolumna que aparece en varias de las tablas que hemos cargado para la consulta, por lo tanto, tendremos queindicar de cuales de dichas tablas queremos que sean obtenidos los datos de dicha columna, como yapreviamente habíamos enlazado las tablas es indiferente el ámbito que le asignemos. Y centrándonos ya en laparte de la consulta que se refiere a este apartado fijaros como indicado en la lista los valores que queremosencontrar, los nombre de las provincias, y como los valores son alfanumérico los hemos escrito entre comillasdobles.

Búsqueda de valores en una cadena (LIKE)

Podemos preguntar por subcadenas dentro de columnas tipo carácter. Para ello usaremos el operadorLIKE y su sintáxis:

WHERE Columna [NOT] LIKE “Expresión”

La Expresión puede estar compuesta por los siguientes signos:

? Letra y números.

Page 25: SQL y Firebird

? %: Cualquier cadena de 0 o más caractéres.

? _: Cualquier carácter individual o ausencia de éste.

? []: Conjunto de caracteres, como [abcdef], o un intervalo de estos, como [a-e]

? [^]: Negación.

Por lo tanto, con los signos citados podemos generar expresiones que representen las posibilidades decadenas que nosotros buscamos.

La cláusula LIKE no se utiliza cuando buscamos una cadena en concreto, o un conjunto de cadenasdeterminadas que no sean parecidas, para eso utilizamos una lista de valores con la sentencia IN. LIKE lautilizaremos cuando busquemos un conjunto de cadenas en las que exista un patrón, donde podamosencontrar una expresión, utilizando los signos permitidos, que nos permita identificar a todas las cadenas delconjunto que buscamos. Dependiendo de lo fácil o complicado que sea encontrar el patrón de las cadenas quebuscamos, optaremos por utilizar LIKE, si es fácil encontrar el patrón, o IN, enumerando la totalidad de lascadenas, si no existe patrón o es muy complicado encontrarlo.

Es muy importante destacar que se diferencia entre mayúsculas y minúsculas.

Encontrar todos los vendedores cuyo nombre es Manuel.

select *from vendedorwhere nomvend like “Manuel %”

Nos vemos obligados a utilizar LIKE puesto que sabemos que el nombre debe de empezar por Manuelpero desconocemos cuales van a ser sus apellidos por lo que tendremos que poner el comodín de las cadenas“%”.

Ahora encontrar todos los vendedores cuyo nombre es Manuel o Manolo

select *from vendedorwhere nomvend like “Man[uel,olo] %”

Hemos encontrado el patrón, ambos nombre comienzan por las letras “Man” y depués el sufijo “uel” o“olo”, y como en el caso anterior, posteriormente “%” puesto que desconocemos sus apellidos.

Encontrar todos los vendedores que uno de sus apellidos sea Pérez.

select *from vendedorwhere nomvend like “% Pérez %”

Como uno de sus apellidos es Pérez, pero desconocemos su nombre y su segundo apellido, en el casoque Pérez fuera el primero, o si es el segundo apellido, desconocemos tanto su nombre como su primerapellido, ponemos “%” tanto delante como detrás. En el caso en el que buscáramos solamente a losvendedores cuyo segundo apellido es Pérez, deberíamos de colocar un solo “%” delante del apellido, puestoque al estar seguros que Pérez es su segundo apellido no habrá ningún texto detrás de éste.

Encontrar todas las piezas cuyo número no empieza por T, tengan a continuación un guión,tres ceros,cualquier número y terminen con cualquier letra.

select *from piezawhere numpieza like “[^T]-000[0-9]%[A-Z]”

Esta ha sido ya, lo reconozco, una búsqueda caprichosa, pero no está de más hacerla y comprobar lapotencia que LIKE nos facilita. Mucha atención a los signos utilizados y el orden de aparición.

Page 26: SQL y Firebird

En Interbase las expresiones compuestas por los signos [ ] o [^] no son soportadas.

Valores nulos (IS NULL)

Cuando se habla de valores nulos, automáticamente se piensa en un carácter en blanco, sin embargo, alhacer esta reflexión caemos en un grave error. Un valor nulo es la ausencia de valor, es decir, cuando a unacolumna no se le atribuye ningún valor. Como casi todos los lenguajes existentes en la actualidad, en SQLtambién existe una palabra reservada que hace referencia al valor nulo, la palabra clave NULL.

Para realizar una consulta sobre los valores nulos de una columna específica basta con seguir la siguientesintaxis:

WHERE Columna IS NULL

Un ejemplo rapidísimo. Obtener todas las piezas que no tengan descuento aplicado.

select *from piezawhere descuento is null

No hay que incurrir en el error típico de hacerlo así: descuento=NULL o descuento=”NULL” puesto quede ninguna de las dos formas obtendremos los resultados esperados.

Funciones de agregado

Las funciones de agregado realizan un cálculo sobre un conjunto de valores y devuelven un solo valor.Con excepción de COUNT, las funciones de agregado omiten los valores nulos. A continuación un listado delas funciones de agregado:

? AVG ([DISTINCT] Expresión): Devuelve la media de los valores de ungrupo. Los valores nulos se omiten.

? COUNT (*|[ALL|DISTINCT] Expresión): Devuelve el número de elementos deun grupo.

? MAX ([ALL|DISTINCT] Expresión): Devuelve el valor máximo de laexpresión.

? MIN ([ALL|DISTINCT] Expresión): Devuelve el valor mínimo de laexpresión. Devuelve la suma de todos los valores o de sólo los valoresDISTINCT en la expresión especificada.

? SUM ([ALL|DISTINCT] Expresión): Devuelve la suma de todos los valoreso de sólo los valores DISTINCT en la expresión especificada. Sólopuede utilizarse con columnas numéricas. Los valores nulos se omiten.

? STDEV (Expresión): Devuelve la desviación típica estadística de todoslos valores de la expresión especificada.

? STDEVP (Expresión): Devuelve la desviación típica estadística de lapoblación para todos los valores de la expresión especificada.

? VAR (Expresión): Devuelve la varianza estadística de todos los valoresen una expresión dada.

? VARP (Expresión): Devuelve la varianza estadística del llenado paratodos los valores en la expresión dada.

Dichas funciones agregadas retornan valores calculados sobre una determinada columna. Estasfunciones devuelven un único valor para todas las tuplas seleccionadas mediante la condición de la cláusulaWHERE, si no se especifica ésta, el cálculo se realiza sobre la totalidad de la columna.

Las funciones estadísticas precisan que la expresión que se evalúe se construya sobre columnas de tipode datos numéricos.

Page 27: SQL y Firebird

Las expresiones pueden contener el nombre de una columna o un cálculo sobre una o varias columnas, Sise especifica la clave DISTINC, la expresión obligatoriamente ha de ser un nombre de columna, y se asumeque la función se calcula únicamente sobre valores distintos de la expresión. Deberemos tener en cuenta queno se pueden anidar funciones, es decir AVG(MIN(preciovent)) no está permitido.

Las funciones de agregado sólo se pueden utilizar como expresiones en: la lista de selección de unainstrucción SELECT, cláusula COMPUTE o COMPUTE BY y en la cláusula HAVING, la cual veremos acontinuación.

También podemos utilizar los operadores aritméticos: + (sumar), - (restar), * (multiplicar), / (dividir) y %(módulo) para realizar cálculos.

Unos ejemplos. Obtener la diferencia entre cantidad pedida y cantidad recibida de las líneas del pedido1.

select (cantpedida-cantrecibida)from linpedwhere numlinea=1

Obtener la cantidad de provincias distintas de las que tenemos conocimiento de algún proveedor.

select count(distinc provincia) from vendedor

Las funciones agregadas las vamos a utilizar en la mayoría de las ocasiones junto con agrupaciones delos datos.

Agrupaciones y selecciones (GROUP BY, HAVING)

Podemos realizar consultas en las cuales se realicen agrupaciones de filas de las tablas que utilizamos.La agrupación consiste en formar subconjuntos dentro de una tabla en función de los valores que tengan losdatos de las columnas por las que deseemos agrupar. Las agrupaciones se realizan con la cláusula GROUPBY, la cual siempre tiene que ir situada inmediatamente detrás de WHERE, o en el caso que no existierainmediatamente detrás de FROM. Su sintaxis es:

GROUP BY Columna1,...,ColumnaN

Cuando realizamos una agrupación, podríamos decir que se forman subconjuntos dentro de la tablaen laque se encuentra la columna por la que agrupamos, de forma que todas las filas que tengan el mismo valordentro de la columna por la que agrupamos formarán parte del mismo subconjunto. Así nos encontraremoscomo resultado tantos subconjuntos como valores diferentes tienen los datos de la columna por la que hemosagrupado. En el caso que agrupemos por varias columnas simultáneamente la explicación anterior se amplíapara varias columnas.

Un dato muy importante es que cuando utilizamos GROUP BY las columnas que aparecen en la cláusulaSELECT pueden ser solamente de dos tipos: columnas agrupadas que aparecen en GROUP BY, o columnasfunciones agregadas aplicadas a cualquier otra expresión o columna.

Veamos un ejemplo. Imaginemos la tabla Linped (línea de pedido), en la cual encontramos un listado contodas las líneas de todos los pedidos que se han realizado. En cada línea encontramos los datos de la piezaque se ha pedido, que cantidad de pieza que se ha pedido, el número de pedido al que pertenece esa línea,etc. Linped no es más que la tabla detalle de su tabla maestra que es Pedido. Si en Linped tuviéramos lossiguientes datos, imaginemos, sólo por el momento, que Linped tiene esta estructura y estos datos:

Número pedido

(numpedido)

Linea pedido

(numlinea)

Número pieza

(numpieza)

Cantidad pedida

(cantpedida)

1 1 AAA 20

1 2 BBB 10

Page 28: SQL y Firebird

Número pedido

(numpedido)

Linea pedido

(numlinea)

Número pieza

(numpieza)

Cantidad pedida

(cantpedida)

1 3 CCC 152 1 AAA 8

2 2 HHH 103 1 BBB 223 2 PPP 10

3 3 AAA 3

Si realizamos un agrupamiento por el número del pedido nos encontraríamos con tres subgrupos: elprimero formado por las filas de las tres líneas de pedido del pedido uno, el segundo subgrupo formado por lasdos filas de las líneas del segundo pedido, y el tercer y último subgrupo formado por las tres filas de las líneasde pedido que pertenecen al pedido número tres.

Si por ejemplo quisiéramos saber el número de líneas que forman cada uno de los pedidos, claramentenecesitaremos utilizar COUNT (numlinea), pero si lo utilizamos sin más, es decir, sin realizar ningunaagrupación, lo que obtendremos será el número de líneas de pedido que hay en la tabla, es decir, su númerode filas. Necesitamos, sin embargo, que el COUNT haga referencia a las líneas de pedido de cada pedido. Sehace necesario que realicemos una agrupación por el número de pedido y así COUNT nos devolverá elnúmero de líneas de pedido de cada uno de los subconjuntos formados:

select numpedido, count(numlinea)from linpedgroup by numpedido

Ya hemos logrado obtener el número de líneas de pedido que forman cada uno de los pedidos. Hemosnecesitado agrupar por el número de pedido, por lo tanto, como lo tenemos en el GROUP BY estamosobligados a ponerlo también en el SELECT. Si intentamos mostrar cualquier otra columna de la tabla Linpedveremos que se genera un error, puesto que estamos mostrar una columna por la que no estamos agrupando,recordar este detalle puesto que en muchas ocasiones incurrimos en este error.

Otro ejemplo. Queremos obtener para cada una de las piezas que hemos pedido en los primeros 100pedidos la cantidad total de unidades que han pedido de cada una de ellas.

select numpieza "Número de la pieza",sum(cantpedida) "Cantidad pedida"from linpedwhere numpedido<=100group by numpiezaorder by numpieza

En esta ocasión no hemos tenido que agrupar por el número de pedido, es un dato que nos nos importaahora, sino que hemos tenido que agrupar por el número de la pieza. Y para obtener la cantidad que se hapedido de cada una de ellas realizamos la suma de todas las cantidades pedidas por cada una de las piezas.Hemos tenido la precaución de renombrar las columnas y ordenar ascendentemente por el número de la piezapara que quede más claro el resultado de la consulta.

Como ya sabemos, disponemos de la cláusula WHERE para imponer condiciones sobre las filas quevamos a mostrar en la consulta, de forma que solamente aquellas filas que cumplan las condiciones marcadasen el WHERE serán mostradas. Los grupos también tienen su propia cláusula para imponer condiciones, lacláusula HAVING. Con HAVING vamos a indicar las condiciones que tienen que cumplir los gruposformados por GROUP BY para que puedan ser mostrados en el resultado de la consulta. HAVING simpreestará situado inmediatamente detrás de GROUP BY. Su sintaxis es:

HAVING Condición1,...,CondiciónN

Page 29: SQL y Firebird

Retomamos los ejemplos anteriores, pero ahora queremos saber el número de líneas que forman cadauno de los pedidos, pero solo de aquellos pedidos en los que se hayan pedido más de cinco unidades entretodas sus piezas.

select numpedido, count(numlinea)from linpedgroup by numpedidohaving min(cantpedida)>5

Y como remate final, vamos a obtener para cada una de las piezas que hemos pedido en los primeros100 pedidos la cantidad total de unidades que han pedido de cada una de ellas siempre y cuando esa pieza lahayamos pedido más de una vez.

select numpieza "Número de la pieza",sum(cantpedida) "Cantidad pedida", count(*)from linpedwhere numpedido<=100group by numpiezahaving count(*)>1order by numpieza

Es la misma consulta que ya habíamos realizado anteriormente sólo que ahora imponemos una condiciónal subconjunto, y es que exista más de una fila. Si existe más de una fila significa que esa pieza se ha pedidomás de una vez, puesto que estamos agrupando por la pieza, por su número, los subgrupos tendrán tantasfilas como veces aparezca esa pieza en la tabla de líneas de pedido, o lo que es lo mismo, el subconjuntotendrá tantas filas como veces se haya pedido la pieza.

¿Y en el próximo articulo qué?.

Esto toca ya su fin. Ya hemos andado el camino, por esta vez. Hemos vistos muchas cosas. Hemoshecho un recorrido amplio por las consultas en SQL, nos han presentado al famoso por excelencia dellenguaje de consultas estándar, SELECT, y de paso, a unos cuantos amigos suyos sin los cuales no podríahacer nada.

Tenemos en nuestras manos las herramientas suficientes para satisfacer la mayoría de los interrogantesque le podemos plantear a los datos de nuestras tablas. Ahora solamente nos resta jugar con estasherramientas y exprimir su posibilidades y su potencia.

Recordar que junto con la revistas disponéis de tres ficheros en los que apoyaros para realizar los juegosque antes comentábamos. El primero, con la base de datos que nos ha servido de ejemplo durante todo elartículo y sobre la que hemos basado muchas de las explicaciones, y los otros dos con propuestas deconsultas que abarcan todos los apartados que hemos tratado y sus correspondientes soluciones. Como sesuele hacer en estos casos, recomendaros que primero intentéis resolver vosotros solos los problemas que seos plantean y después miréis las soluciones, y como siempre, lo haréis al revés, pero en fin, yo también loharía.

En el próximo número continuaremos con SQL embarcándonos esta vez en las consultas anidadas, quese trata de pasarle a una consulta el resultado de otra consulta y que estos datos devueltos por la primera detodas, la subconsulta, sirva a la segunda para satisfacer una serie de condiciones impuestas. Ademásconoceremos las vistas y los procedimientos almacenados. Todo un mundo nos espera aun.

Ha llegado ya el momento de la despedida, como siempre, espero haber sido de ayuda a que conozcáismejor SQL y os emplazo al próximo número de la revista SINTESIS donde nos volveremos a encontrar.

Un saludo, muchas gracias y hasta pronto.

Page 30: SQL y Firebird

SQL. Vistas y procedimientos.Óscar Javier Segura Amorós [email protected]

Ya estamos aquí un número más para continuar viendo este maravilloso lenguaje de base de datos que esSQL.

Hasta este número, a través de los artículos publicados en los números anteriores de SÍNTESIS, hemosempezado a conocer SQL, su propósito, su estructura, su utilización y sus instrucciones. Con el artículo dehoy llegamos ya al final del camino, aunque no terminaremos de andarlo del todo, por si en el futuro queremosseguir paseando por estos paisajes.

Hoy vamos a conocer las vistas y los procedimientos almacenados, intentaremos dar una visión amplia depara qué nos pueden servir, y después profundizar ya más en la sintaxis y peculiaridades de ambos.

Una buena utilización de las vistas y los procedimientos en el gestor de nuestras bases de datos nos va aaportar una mayor sencillez en la programación de las aplicaciones que van a trabajar con las bases de datos,sobre todo si nos encontramos en estructuras cliente/servidor y si a una misma base de datos se le atacadesde aplicaciones diferentes. Vamos a conseguir optimizar nuestro trabajo.

Tenemos que intentar que la mayoría del trabajo que hay que hacer contra la base de datos la realice elgestor de la base de datos en el servidor. No es muy correcto obtener todos los datos del servidor, pasarlos ala aplicación y una vez que los tenemos ya en la aplicación analizarlos, tratarlos y quedarnos solamente conlos necesarios, con esta política estamos produciendo una sobrecarga en la red o en el canal de transferenciade datos utilizado y además estamos relentizando el funcionamiento de nuestra aplicación. Hay que intentardistribuir el trabajo entre los diferentes elementos que conforman nuestro sistema informático, haciendo quecada uno de ellos cumpla con los cometidos para los que existe y para los que por tanto está preparado.

El gestor de la base de datos tienen la razón de ser, no solamente para mantener la base datos y atendernuestras peticiones de información, sino también para desahogar el funcionamiento de los clientes, y eso lotenemos que tener muy claro.

En el artículo de este número, a través de las vista y los procedimientos vamos a ver como podemoseliminar cierta programación del cliente y situarla sobre el servidor, optimizando así nuestro trabajo yconsiguiendo una aplicación más rápida, y más fácil de mantener y acturalizar. Programación referida nosolamente al análisis y tratamiento de los datos, sino también a la seguridad e integridad de los mismos.

Vistas

Una vista es una consulta almacenada, una estructura SELECT permanente dentro de la base de datos.Permanente desde el momento que se crea hasta el momento que se elimina, si éste último llega a producirse.Tanto la creación como el borrado de la vista depende del administrador de la base de datos, o en su defecto,del usuario de la misma.

Los datos que la vista devuelve, es decir, los datos que forman el dominio de la consulta, se van aconformar en lo que podríamos denominar una tabla virtual; tabla, porque vamos a poder trabajar con esosdatos como si pertenecieran a una tabla más de nuestra base de datos, pudiendo sobre ellos realizarinserciones, borrados, actualizaciones, incluso consultas, y virtual porque en realidad no es una tablapropiamente dicha de nuestra base de datos aunque podamos trabajar con ella como tal.

Las vistas, principalmente las vamos a utilizar para las siguientes funciones:

Page 31: SQL y Firebird

? Restringir al usuario a filas concretas de una tabla. Por ejemplo, hacer que un empleado sólo vealas filas que guardan sus datos en una tabla de seguimiento de actividad laboral sin que pueda verlos datos del resto de compañeros.

? Restringir al usuario a columnas específicas. Por ejemplo, en la tabla de personal donde tenemostodos los datos de cada trabajador mostrar solamente los referentes a nombre, dirección, teléfonoy e-mail, no mostrando los datos más sensibles, permitiendo acceder solamente a esos datos aempleados con un grado de responsabilidad y mando superior, haciendo esto posible a través deotra vista o dando los permisos pertinentes para que éste pueda trabajar con la tabla de personaldirectamente.

? Combinar columnas de varias tablas de forma que parezcan una sola. Por ejemplo, para usuariosnoveles facilitarles el trabajo con las consultas o para no permitir que conozcan plenamente laestructura de la base de datos.

? Agregar información en lugar de presentar los detalles. Por ejemplo, presentar la suma de unacolumna, su valor máximo o mínimo en lugar de presentar todos los valores individuales.

? Dejar de forma permanente hechas las consulta más usuales de los usuarios para que las puedanejecutar de forma rápida, evitando de esta forma, que tengan que teclear cada días las mismasconsultas o recuperarlas de un fichero de scripts de SQL.

? Filtrar la inserción de nuevos datos en la base de datos o filtrar las modificaciones de los yaexistentes de forma que solamente se pueda trabajar con un subconjunto definido de los datos. Porejemplo que el personal del departamento de publicidad solamente pueda trabajar con los datos deaquellos trabajadores que en la tabla de contratos aparecen contratados para dicho departamento.

? Por motivos de seguridad. Podemos generar vistas que den acceso a subconjuntos de tablas ocolumnas de nuestra base de datos y después asignar a cada usuario permisos para poder utilizardeterminadas vistas. De esta forma estamos ofreciendo a cada tipo de usuario accesoexclusivamente a los datos que les hacen falta evitando de así que un usuario pueda ver o trabajarcon datos que en principio él no tendría que conocer o poder modificar.

Creación de vistas (CREATE VIEW)

Crear una vista es tan sencillo como crear la consulta que queremos que almacene dicha vista,anteponiendo la cláusula CREATE VIEW. La sintaxis para la creación es:

CREATE VIEW nombre_vista [(columna1, ..., columnaN)]ASSELECT expresiónFROM tabla1, ..., tablaN, vista1, ..., vistaN[WHERE expresión][GROUP BY [ALL] expresión1, ..., expresiónN][HAVING condición][WITH CHECK OPTION]

Una vez que hemos creado la vista, los datos que la consulta devuelve se convierten en una tabla, comoanteriormente explicaba, cuyo nombre es el nombre que le hemos asignado a la vista y por lo tanto podemoshacer referencia a ella utilizando el nombre de la misma. Por ejemplo, si quisiéramos ver todos los datos quedevuelve la vista, simplemente tenemos que hacer una consulta, y dicha consulta la hacemos como si lahiciéramos para una tabla cualquiera.

SELECT *FROM nombre_vista

A continuación profundizaremos en cada apartado de la estructura de la creación de la vista.

Page 32: SQL y Firebird

? El nombre de la vista debe de cumplir las reglas de los identificadores. Especificar el nombre delpropietario de la vista es opcional.

? Las columnas son los nombres que se van a utilizar para las identificar a las columnas de la vista.Asignar un nombre a una columna sólo es necesario cuando la columna se derive de unaexpresión aritmética, una función o una constante, cuando dos o más columnas pueden tener elmismo nombre, debido normalmente a una combinación, o cuando la columna de la vista recibe unnombre distinto al de la columna de la que se deriva. Los nombre de las columna las podemosasignar también en la consulta, tras la cláusula SELECT como se hace en las consultas, sin nosresulta más sencillo.

Si no especificamos ningún nombre a las columnas, estas adquirirán el nombre de la columna de laque se derivan.

? Tras el comando AS escribiremos la consulta que almacenará la vista.

? En la instrucción SELECT definimos la vista. Podemos utilizar consultas sencilla o complejas, conuna tabla o con varias, podemos trabajar también con otras vistas utilizándolas como simplestablas, las únicas restricciones que tenemos, las únicas cosas que no podemos utilizar en lasconsultas que definen una vista es la utilización de las cláusulas ORDER BY, COMPUTE oCOMPUTE BY, la utilización de la palabra clave INTO y hacer referencias a tablas temporales.

? El argumento WITH CHECK OPTION exige que todas las instrucciones de modificación dedatos ejecutadas contra la vista cumplan los criterios establecidos en el apartado SELECT. Sinosotros estipulamos en la consulta una serie de condiciones, en el futuro, a la hora de realizaralguna actualización de los datos, bien sea modificándolos o insertando datos nuevos, no podremosllevarla a cabo si dicha actualización no supera las condiciones establecidas.

Es una buena forma de filtrar las modificaciones e inserciones en nuestras tablas, de forma quecontrolamos sobre que subdominios de datos del dominio original de la tabla el usuario puedetrabajar.

Con el argumento WITH CHECK OPTION hay que tener un poco de cuidado.

Imaginemos la situación de una empresa donde existen dos administrativos, uno dedicado exclusivamentea las cuentas de grandes clientes y otro dedicado a las cuentas de clientes pequeños y medianos, laclasificación se establece en función del volumen de compra anual que dichos clientes nos realizan. Para quecada uno de los administrativos tenga acceso solamente a los datos de los clientes con los que tienen quetrabajar, una solución, es crear dos vistas, una vista trabajará con los clientes cuya compra anual sea superiora una cierta cantidad y la otra vista trabajará con el resto de clientes. De esta forma no tenemos que creardos tablas de clientes diferentes, la estructura de la base de datos no se tiene que modificar. Si un día eladministrativo que se ocupa de los grandes clientes no puede ir a trabajar y hace falta dar de alta a un nuevo“gran cliente”, se puede ocupar el otro administrativo, ¿pero qué ocurrirá?. Pues muy sencillo, cuando elsegundo administrativo de alta al nuevo cliente y quiera comprobar sus datos, éste no le aparecerá por ningúnsitio, y si intenta volver a darle de alta, el sistema le dirá que ya existe, ¡para volverse loco!, pensará, y comosiempre terminará culpando al informático. ¿Qué ha ocurrido?, el alta del nuevo cliente se ha realizado sinningún problema, ya está introducido en la base de datos, pero como el administrativo trabaja con la tabla declientes a través de una vista, y esta le muestra solamente un subconjunto de los datos, a él le parece que noha conseguido introducir al nuevo cliente. Veamos cuales podrían ser las vistas de esta situación.

CREATE TABLE CLIENTES(CODIGO INTEGER NOT NULL,NUM_IDEN_FISCAL VARCHAR(10) NOT NULL,NOMBRE VARCHAR(40),DIRECCIÓN VARCHAR(80),CIUDAD VARCHAR(30),TELEFONO VARCHAR(9),COMPRA_ANUAL INTEGER,

CONSTRAINT CP_CLIENTES PRIMARY KEY (CODIGO),

Page 33: SQL y Firebird

CONSTRAINT CALT_CLIENTES UNIQUE KEY (NUM_IDEM_FISCALN),CONSTRAINT CAJ_CLIENTES FOREING KEY (COMPRA_ANUAL) REFERENCES (PREVISIONES)

)

CREATE VIEW VISTA_CLIENTES_GRANDESASSELECT * FROM CLIENTESWHERE COMPRA_ANUAL >= 10000000

CREATE VIEW VISTA_CLIENTES_PEQUEÑOSASSELECT * FROM CLIENTESWHERE COMPRA_ANUAL < 10000000

Para evitar la situación que he descrito podríamos haber utilizado el argumento WITH CHECKOPTION. Si creamos las vista utilizando este argumento, estamos obligando a que en el futuro cuandoqueramos realizar una modificación o una inserción, éstas van a tener que cumplir los criterios establecidos enla vista. En el ejemplo concreto, si la hubiéramos utilizado, el administrativo al intentar dar de alta al cliente nohubiera podido, puesto que el administrativo va a realizar la inserción contra la vista de clientes pequeños porlo que el cliente no va a satisfacer la condición impuesta en el campo de COMPRA_ANUAL. Como no sehabía establecido el argumento de chequeo, la inserción se puede realizar perfectamente, pero a la hora decomprobar los datos, el nuevo dato no aparecerá, no porque no exista, sino porque la vista no lo tiene quemostrar. En nuestro caso, cuando el administrativo de los clientes grandes se vuelva a incorporar al trabajo yejecute su vista podrá comprobar que efectivamente su compañero si que había insertado al nuevo cliente,por más que éste le repita que no entiende lo que ha sucedido porque él no conseguía el día anterior verlo y alfinal le terminará costando el puesto al informático.

Borrado de vistas (DROP VIEW)

Para eliminar una vista, o varias, utilizamos la cláusula DROP VIEW, que se usa de una forma tansencilla como:

DROP VIEW nombre_vista1, ... , nombre_vistaN

Cuando borramos la vista, lo único que se elimina es ésta, es decir, las tablas o vistas con las que estabarelacionada permanecen intactas y podemos continuar utilizándolas sin ningún problema. No sucede lo mismosi lo que hacemos es borrar una tabla o vista que era utilizada por otra vista. Cuando se da esta situación nospueden ocurrir dos cosas, dependiendo del sistema gestor de bases de datos que utilicemos:

? Si utilizamos SQL Server, por ejemplo, al borrar la tabla, la vista que la utilizaba permaneceráintacta, pero al intentar utilizar la vista, el gestor nos devolverá un mensaje de error indicando quealguna de las tablas que se utilizan en la vista ya no están disponibles, por lo que no podremostrabajar con ella, no tiene fuente de datos de obtener los resultados.

Al no haberse borrado la vista, ya que simplemente se queda inutilizada, si volvemos a crear latabla, podremos volver a utilizar la vista sin ningún problema. Aquí solamente hay que tener laprecaución de crear la tabla con el mismo nombre y como mínimo, con los mismos campos que seutilizan en la vista.

? Si utilizamos Interbase 6, por ejemplo, al intentar borrar la tabla, el gestor nos devolverá unmensaje de error indicándonos que no podemos borrar la tabla porque hay algún elemento

Page 34: SQL y Firebird

asociado a ésta, tendremos previamente que borrar la vista, para a continuación poder borrar latabla.

Las dos políticas que se utilizan cuando se da la situación de borrar una tabla que tiene asociada una vistason las descritas en los puntos anteriores. Hemos citado el ejemplo de dos gestores concretos, pero el restode gestores se acogen a uno de los dos funcionamientos mencionados.

Continuando con el ejemplo del apartado anterior, podríamos borrar las dos vistas inclusosimultáneamente:

DROP VIEW vista_clientes_grandes, vista_clientes_pequeños

Procedimientos almacenados

Un procedimientos podríamos decir que es una evolución de las vistas, imaginemos una vista queadmitiese parámetros para poder acotar la consulta de forma dinámica, pues ya tenemos un procedimiento.

Los procedimientos almacenados de SQL son similares a los procedimientos de otros lenguajes deprogramación en el sentido de que puede:

? Aceptar parámetros de entrada y devolver varios valores en forma de parámetros de salida.

? Contener instrucciones de programación que realicen operaciones en la base de datos, incluidaslas llamadas a otros procedimientos.

? Devolver un valor de estado para indicar si la operación se ha realizado correctamente o hahabido algún error.

Los procedimientos almacenados tienen ventajas e inconvenientes, como todo en esta vida. Las ventajas:

? Ayudan a mantener la consistencia de la base de datos. Si dejamos al usuario que campe a susanchas con las instrucciones de actualización, UPDATE, INSERT y DELETE, corremos el riesgoque no siempre se cumplan las reglas de consistencia. Una forma de evitarlo es trabajando lasactualizaciones a través de procedimientos, puesto que tenemos un control de cómo se va arealizar ese proceso.

? Reducen el tráfico en la red. Los procedimientos se ejecutan en el servidor por lo que no tenemosque recibir tablas enteras de datos para realizar después nuestros análisis, el análisis de los datosse ha realizado ya en el servidor y nosotros recibimos simplemente los datos que necesitamos.

? Ahorramos tiempo de desarrollo. Es normal que en una estructura cliente-servidor variasaplicaciones trabajen con la misma base de datos Si programamos en la propia base de datos lasreglas de consistencia nos ahorramos tener que repetir la misma programación en las distintasaplicaciones, con lo que también disminuimos las posibilidades de errores u olvidos de reglas.

? Si creamos procedimientos almacenados que son utilizados por una o varias aplicaciones, es másfácil, llegado el momento, cambiar la programación del procedimiento que cambiar laprogramación de la totalidad de las aplicaciones.

? Ejecución más rápida puesto que el procedimiento es compilado y optimizado en el momento de sucreación y después podemos utilizarlo ya directamente tantas veces como queramos. Si por elcontrario utilizamos lotes de comandos de SQL, cada vez que los utilizamos se tienen que compilary optimizar.

Page 35: SQL y Firebird

Creación de procedimientos (CREATE PROCEDURE)

Para la creación de un procedimiento utilizamos la cláusula CREATE PROCEDURE, pero dependiendodel gestor que vayamos a utilizar encontramos unas pequeñas diferencias. Vamos a ver la sintaxis para SQLServer e Interbase, por coger dos de los más utilizados.

Para SQL Server

CREATE PROCEDURE nombre_procedimiento[@variable1 tipoDato, ... , @variableN tipoDato [OUTPUT]]ASInstrucciones SQL

Para Interbase

CREATE PROCEDURE nombre_procedimiento [ (variable_entrada1 tipoDato, ..., variable_entradaN tipoDato)][ RETURNS (variable_salida1 tipoDato, ..., varialbe_salidaN tipoDato) ]AS[ DECLARE VARIABLE variable_local1 tipoDato; DECLARE VARIABLE variable_localN tipoDato; ]BEGINInstrucciones SQLEND

El nombre_procedimiento es el nombre del nuevo procedimiento almacenado, utilizaremos este nombrecada vez que queramos referirnos a él, bien sea para ejecutarlo o para borrarlo. Los nombre deprocedimientos deben seguir las reglas de los identificadores y deben de ser únicos en la base de datos.

Las variables, son los parámetros del procedimiento. Cuando creamos un procedimiento podemosdeclarar una o varias variables y cuando ejecutamos el procedimiento el usuario debe de asignar los valorescorrespondientes a dichas variables y en el orden en las que estas han sido declaradas. En SQL Server elnombre de las variables siempre empieza por el signo @, no siendo así en Interbase. Las variables son localesal procedimiento por lo que podemos declarar variables con el mismo nombre en procedimientos diferentes.

El tipoDato en la declaración de una variable es el dominio de dicha variable.

Los procedimientos pueden devolver valores a la ejecución del mismo. La devolución de estos valores,que no serán más que variables, se deben de indicar en el momento de la declaración de las mismas. Aquíencontramos otra diferencia de sintaxis entre gestores, en SQL Server se debe de utiliza la cláusulaOUTPUT al lado de la variable que queremos que retorne su valor, y en Interbase, este tipo de variablesdeben de declararse separadas de las variables de entrada y después de la cláusula RETURNS. Salvo lasdiferencias sintácticas es exactamente lo mismo.

AS son las acciones que va a llevar a cabo el procedimiento.

DECLARE VARIABLE, nos sirve para poder declarar variables locales para utilizar en el bloque deinstrucciones SQL.

Instrucciones SQL son las instrucciones de SQL que se incluirán en el procedimiento. Aquí existealguna limitación, no todas las cláusulas de SQL tienen cabida aquí, depende de cada gestor de bases dedatos exactamente que instrucciones son aceptadas y cuales no y en qué forma se aceptan.

De forma predeterminada, los parámetros admiten el valor NULL. Si se pasa una valor de parámetrocomo NULL y ese parámetro se utiliza en una instrucción CREATE o ALTER TABLE que hacer referenciaa una columna que no admite valores NULL, se generará un error.

Page 36: SQL y Firebird

Principales instrucciones SQL permitidas en los procedimientos

A continuación vamos a comentar las principales instrucciones de SQL que son soportadas en losprocedimientos. Como ya hemos podido comprobar anteriormente en la creación del procedimiento, puedenexistir diferencias entre los distintos gestores de bases de datos, yo voy a centrarme en Interbase, aunque lasdiferencias con otros gestores en la mayoría de las instrucciones es nula o mínima.

? Asignaciones a las variables de expresiones. Las variables serán cualquiera de las declaradas enla creación del procedimiento.

Variable = Expresion

? Llamadas a procedimientos, con la precaución de que no se admiten expresiones en losparámetros

execute procedure nombre_procedimiento [ parametros de entrada ] [ returning_values parametros de salida ]

? Condicionales

if (condición) then instrucción [ else instrucción ]

? Bucles controlados por condición

while (condición) do instrucción

? Instrucciones SQL. Podemos incluir cualquier condición de manipulación de datos. Estasinstrucciones pueden utilizar variables locales y parámetros, siempre que éstas estén precedidasde dos puntos “:”, para que se puedan diferenciar las variables y parámetros de los nombres decolumnas.

update nominas set monto = monto * :plus where comisiones > 10000;

Se pueden utilizar instrucciones select siempre y cuando devuelvan una sola fila, parainstrucciones más generales utilizaremos la instrucción for. Si queremos transferir valores avariables o parámetros lo haremos con la cláusula into.

select nombre from clientes where codigo = 23445into :nombre_empresa;

? Iteración sobre consultas. Recorremos el conjunto de filas definido por la instrucción select. Paracada fila, transfiere los valores a las variables de la cláusula into, de forma similar a lo que sucedecon las selecciones únicas, y ejecuta entonces la instrucción de la sección do.

for instruccion_select into variables do instrucción

? Instrucciones de control. La instrucción exit termina la ejecución del procedimiento actual. Lainstrucción suspend, se utiliza con procedimientos que devuelven un conjunto de filas a la rutinaque lo ha llamado, suspende temporalmente el procedimiento, hasta que la rutina que lo llama hayaprocesado los valores retornados.

exit;suspend;

Page 37: SQL y Firebird

Borrado de procedimientos (DROP PROCEDURES)

Para eliminar uno o más procedimientos almacenados utilizamos la cláusula DROP PROCEDURE:

DROP PROCEDURE procedimiento1, ... , procedimientoN

Ejecución de procedimientos (EXECUTE)

Para ejecutar un procedimiento..., así de sencillo:

EXECUTE PROCEDURE nombre_procedimiento [parámetro1, ... , parámetroN]

Si no tenemos muchas ganas de escribir, en lugar de EXCUTE podemos utilizar EXEC y a continuaciónlos valores que queremos darle a los parámetros. Recordar que los valores de los parámetros tienen quepasarse al procedimiento en el mismo orden en el que han sido definidos en el momento de la creación delmismo.

El carácter de terminación (SET TERM)

Si vamos a introducir los procedimientos almacenados en la base de datos a través de un fichero script esnecesario que utilicemos un carácter de terminación para que la aplicación que vayamos a utilizar para tal finsepa diferenciar cuando termina un bloque de instrucciones y comienza otro. El carácter de terminación loestablecemos nosotros a través de la cláusula SET TERM.

SET TERM terminador

El carácter terminador por defecto es el punto y coma “;”, ahora bien, en los procedimientos tenemosque introducir los bloques de instrucciones SQL, por lo que aparecerán caracteres de terminación quepertenecen a los diferentes apartados del bloque de instrucciones pero no indican que ha terminado elprocedimiento. Sin embargo la aplicación que utilicemos para introducir el script tomará estos terminadorescomo marcas de que ha terminado el procedimiento almacenado. Este es el motivo de tener que cambiar elcarácter de terminación.

Como carácter terminador tendremos que escoger uno que no vayamos a utilizar en el resto del script,normalmente se utiliza el acento circunflejo “^”.

SET TERM ^ ;

Como el cambiar el carácter de terminación también es una instrucción de SQL, tendremos que ponerleel punto y coma “;”, señal de que termina. De ahora en adelante, hasta que lo volvamos a cambiar, cadainstrucción que escribamos irá finalizada por “^”. Para reponer todo a su sitio y dejarlo como ha sido siempretendremos que volver a cambiar el carácter de terminación.

SET TERM ; ^

Fin (THE END)

Ya hemos dado un paseo por las vistas y los procedimientos almacenados. Espero que compartáis la ideade la distribución del trabajo que apuntaba en la introducción del artículo, y que al igual que yo,penséis que

Page 38: SQL y Firebird

cada elemento del sistema informático tiene una función, y que tenemos que hacerla servir para un mejorfuncionamiento general.

Un saludo y hasta pronto.

Óscar J. Segura Amorós [email protected]