Sie sind auf Seite 1von 38

S Q L

Óscar Javier Segura Amorós

oscarjsa@hotmail.com

Cedida su publicación a el Rinconcito de Delphi

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

SQL. El lenguaje universal de las Bases de Datos.

Óscar Javier Segura Amorós - oscarjsa@hotmail.com

Vamos a conocer SQL, un lenguaje de definición y manipulación utilizado por todas las grandes Bases de Datos.

SQL (Standard Query Language, Lenguaje de consultas estándar o estructurado), es un lenguaje que nos permitirá operar con nuestras bases de datos de una forma sencilla y potente. Se encuentra muy difundido y es 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 su estandarización, no es necesario que cuando nos encontramos ante diferentes sistemas gestores tengamos que aprender como funciona cada uno de ellos de una forma más o menos detallada, simplemente debemos conocer como se trabaja con SQL, ya que su sintaxis y estructuración sufre muy pocas variaciones de un sistema otro. Por lo tanto SQL nos ofrece una única forma de trabajar con independencia del sistema con el que 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 y posibilidades que nos brinda, vamos a imaginar la siguiente situación. Imaginemos que hemos diseñado una base de datos para un grupo de clientes. El diseño de ésta, lógicamente, debe de ser independiente del sistema gestor en el que vaya a funcionar, pero qué ocurre cuando llegamos al cliente con el diseño hecho y tenemos que montarlo. Si tenemos la suerte de conocer el sistema gestor que el cliente utiliza, no tenemos ningún problema, pero qué pasa cuando no lo conocemos, perdemos mucho tiempo. Además, si la misma base de datos la vamos a montar para diferentes clientes, lo normal es que nos encontremos con diferentes gestores. Pues este inconveniente, que en principio para el programador puede ser un problema, SQL nos lo resuelve. Si conocemos SQL, podremos llegar al cliente con los scrips de SQL en los que tenemos ya escritos todas las sentencias necesarias para: crear la base de datos, crear todas las tablas y relaciones, todos los tipos de 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 problemas porque 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 como un 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én nacido. Ya en 1987, 1992, 1995, 1996 se le confirió la estandarización a través de las normas ISO, hasta la actualidad, en la que todo sistema SQL se basa en el estándar SQL-3 (ISO-99) en el que se le han añadido nuevas 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 sintaxis de las sentencias en los diferentes sistemas gestores. Estas diferencias repito que son mínimas y una vez realizados los scrips de SQL que, por ejemplo, diseñan una base de datos, tendremos que hacer muy pocas variaciones si queremos que esos scrips se ejecuten en diferentes sistemas gestores Emplazo al lector para siguientes artículos en los que abordaré las diferencias más notables entre los principales sistemas gestores de bases de datos SQL, en los que trataré de orientarlo sobre la variaciones sintácticas con las que nos vamos a encontrar. Insisto de nuevo en que esas diferencias son mínimas, tan mínimas que no llegan a ser un inconveniente para la utilización de SQL.

Funcionamiento de las bases de datos SQL

Siempre que realicemos un aplicación que vaya a trabajar sobre una base de datos, ésta la situaremos dentro de un servidor de base de datos. El servidor puede ser una máquina dedicada, cuya única función sea la de atender peticiones de sus clientes, devolviéndoles la información y ejecutando los procedimientos ordenados por estos sobre la base de datos. O también el servidor puede ser la misma máquina sobre la que corra la propia aplicación. Dependerá ya de la estructura e importancia del sistema informático sobre el que vaya 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 las funciones 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 por encima, 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 de

datos estará instalada en el servidor y será únicamente el servidor de SQL el que acceda a ésta. Cuando nuestra aplicación realice una llamada a una sentencia SQL no será ella quien la ejecute. Esa sentencia llamará al cliente de SQL que tenemos instalado en nuestra máquina y será él quien se ponga en comunicación con el servidor de SQL. Una vez que el servidor SQL ha recibido la petición del cliente la ejecutará sobre la base de datos, y el resultado de la ejecución será devuelta al cliente que se la pasará a la aplicación. Es el funcionamiento clásico de una distribución cliente-servidor. No es el momento de ensalzar las 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 llamada al cliente con la sentencia SQL hasta que éste le devuelve los datos, es mayor que si la aplicación trabajara directamente con la base de datos, de todas formas tampoco quiero dar la impresión de que el retardo de tiempo es importante, porque es mínimo. Pero en contraposición encontramos muchas ventajas, sobre todo cuando van a ser varios los usuarios que utilizando simultáneamente nuestra aplicación trabajen con la base de datos, ventajas como: la integridad de los datos, la recuperación ante fallos, las inevitables colisiones, las transacciones, etc.

Las instrucciones de SQL

Las instrucciones de SQL las podemos dividir en dos grandes grupos: las instrucciones que trabajan con la estructura de los datos, Lenguaje de definición de datos (LDD), y las instrucciones que trabajan con los datos 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 definidos

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

Comenzaremos conociendo las instrucciones de definición de datos y continuaremos viendo las de manipulación. Para hacer más fácil el aprendizaje vamos a trabajar sobre una hipotética base de datos. Una base de datos sencilla que nos va a permitir reflejar las explicaciones que se realicen sobre SQL en un ejemplo 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 el

próximo las instrucciones de manipulación de esos datos. De todas formas, al final de esta entrega daremos una pequeña pincelada a las instrucciones de manipulación para que el lector vaya introduciéndose un poco en ellas y nos sirva de cierto avance o introducción para la parte de SQL, que de momento, nos vamos a quedar sin conocer.

Diseño de una base de datos

Aunque no es estrictamente el tema de este artículo voy a nombrar brevemente los pasos que debemos

seguir cuando vamos a diseñar una base de datos. De la misma forma que ya he hecho anteriormente, vuelvo

a 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 directamente al interfaz del sistema gestor a comenzar a introducir tablas, atributos y relaciones. Gran error, aunque nos encontremos en la era de las nuevas tecnologías debemos todavía comenzar nuestro trabajo con unos folios en blanco y un lápiz, mejor gastar un poco de tiempo al principio que desesperarnos cuando estamos terminando el trabajo porque nos hemos dado cuenta que tenemos errores de diseño, normalmente estos errores son muy difíciles de solucionar, cuando al no detectarlos previamente hemos basado todo nuestro diseño y trabajo sobre ellos.

Cuando tenemos que realizar el diseño de una base de datos comenzaremos por reunirnos con el cliente

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

“Figura 1” podemos ver el EER de nuestra base de datos. Figura 1. Modelo lógico, esquema

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 del esquema lógico nos aseguramos una metodología, un formalismo y evitamos los errores de diseño típicos que siempre aparecen cuando estos se realizan de forma intuitiva.

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

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 la integridad referencial. El concepto de Clave Primaria significa que el valor de dicho campo sirve de valor de identificación de ese registro dentro de la tabla, de forma que el dato en él introducido no puede ser nulo ni estar repetido en otro registro de la misma tabla.

En la tabla Clientes su Clave Primaria es el DNI (Documento Nacional de Identidad) porque todos los clientes 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, segunda condición de la Clave Primaria.

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

En la tabla Artículos el campo IVA (Impuesto sobre el Valor Añadido) hace referencia a este impuesto que 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 y las relaciones que existen entre las diferentes tablas. Las relaciones las tenemos plasmadas a través de los campos de Clave Ajena que nos indican con que tabla estará relacionado el campo que sufre la clave. Los campos que llevan la característica de Valor no nulo nunca pueden dejarse en blanco. Si nos fijamos, estos campos son Claves Ajenas, por lo tanto lo que estamos consiguiendo es obligando a que siempre exista la relació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 y algú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 uno de los elementos.

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

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

Indica que el elemento anterior se puede repetir n veces. Los elementos se separan

[,

n]

mediante comas.

[

n] Indica que el elemento anterior se puede repetir n veces. Los elementos se separan

mediante espacios en blanco.

Negrita Nombre de bases de datos, tablas, índices, procedimientos almacenados, programas, tipos de 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 decir en los elementos que el usuario crea y que por lo tanto debe de nombrar, no se pueden introducir espacios en blanco, lo normal es sustituir esos espacios en blanco por el carácter de subrayado ,'_', o comenzar la siguiente palabra por una letra mayúscula. Ejemplo: Lineas Pedido, sería incorrecto, podríamos nombrar esta tabla como Lineas_Pedido, o LineasPedido . A lo largo del artículo yo utilizaré cualquiera de las dos formas 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 el nombre 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 tabla más de una clave del mismo tipo irían numeradas, cp_nombre_tabla1, cp_nombre_tabla2,

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 la base de datos. Hasta que no creamos la base de datos no podemos comenzar a crear las tablas y demás elementos. La creación de la base de datos se hará una única vez. Normalmente el proceso de creación se hace desde el entorno visual del sistema gestor pero no existe ningún inconveniente en hacerlo utilizando comandos SQL. Si lo hacemos desde SQL el comando de creación es CREATE DATABASE , y su sintaxis:

CREATE DATABASE nombre_base_datos

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

En los sistemas gestores a la hora de crear nuestra base de datos debemos de estar situados en la base de 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 primera

vez, cada vez que queramos trabajar con ella tendremos que establecer la conexión entre nuestro cliente de

Este proceso, al igual que el proceso de creación, se suele realizar desde el

SQL y el servidor de SQL.

interfaz gráfico. Normalmente el sistema gestor nos ofrece un menú desplegable con todas las bases de datos existentes donde seleccionamos la base de datos con la que vamos a trabajar. El comando SQL equivalente a

este proceso es CONNECT, y su sintaxis:

CONNECT DATABASE nombre_base_datos

Con el comando CONNECT sí vamos a encontrar diferencias importantes dependiendo del sistema gestor 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 principio

o

es lo adecuado. Solamente encontraremos

alternativas, puesto que por definición estos campos siempre tiene que tener valor, nunca pueden estar vacíos. Por ello, en estas columnas estaremos obligados a añadirles la opción NOT NULL, que obliga a que

problemas con

los campos

que sean claves primarias

esos campos no admitan valores nulos. Esa opción también tendremos que utilizarla en los campos que sean claves ajenas y estemos obligados a que todos los registros de nuestra tabla estén relacionados a través de esa 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 gran variedad de tipos de datos, aunque como ocurre siempre, nos acostumbramos a utilizar unos pocos y si en alguna ocasión necesitamos plasmar alguna situación un poco más especial recurrimos a la ayuda de SQL para ver más detalladamente otros tipos de datos o nos creamos los nuestros propios.

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

Integer

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

Smallint

enteros comprendidos 0 y 255.

Tinyint

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

Real

fechas.

Datetime

caracteres fijos hasta 8.000.

Char

caracteres variables hasta 8.000.

caracteres variables hasta 231 - 1 (1.147.483.647).

Varchar

Text

Un pequeño comentario sobre los tipos de datos. La diferencia entre caracteres fijos (Char) y caracteres variables (Varchar) estriba en que si nosotros hacemos con Char una reserva de memoria de 50 posiciones y al introducir datos solamente utilizamos 20, el resto será memoria desperdiciada, mientras que si hemos realizado la reserva utilizando Varchar, caracteres variables, si al final solamente utilizamos 20, el resto de memoria será liberada. Lo más adecuado es utilizar siempre para caracteres Varchar, utilizando Char solamente en aquellos casos en que sepamos de antemano que siempre se va a consumir todo el espacio reservado, 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 sistema gestor vaya controlando su valor e incrementándolo o decrementándolo de forma automática, sin que nosotros tengamos que preocuparnos por ello, tenemos que utilizar la opción IDENTITY. Esta opción necesitará dos parámetros, la inicialización, el valor por el que tiene que comenzar, y el incremento, en el que indicamos el valor 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 e irá incrementando de uno en uno.

Y como no hay mejor forma de aprender que trabajando un poco, vamos a ver como serían los comandos 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)

Fijémonos en la creación de tabla que acabamos de realizar, y destaquemos algunos detalles. El DNI es la clave primaria, así queda definido en la última línea de la instrucción de creación de la tabla, además, a esta clase, se le ha dado el nombre de cp_Clientes, como ya se había recomendado en el apartado de Convenciones de diseño. Si la clave primaria de nuestra tabla Clientes es el DNI, por definición este campo nunca podrá contener valores nulos, por lo que vamos a tener que indicárselo, indicación que hacemos, tal como 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 el número de factura se irá generando automáticamente comenzando por el número de factura 1 y creciendo de uno en uno. También nos encontramos la definición de una clave ajena, el campo DNI será una clave ajena qe 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 el mismo solamente que numerados para que no haya error. Además a los campos de estas dos claves ajenas se les ha asignado la característica de no poder tomar valores nulos. Por lo tanto, siempre que exista una línea de factura ésta va a tener que pertenecer a una factura y ser de la venta de un artículo, no pueden existir líneas de factura que no cumplan estas condiciones.

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

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 uno de los procesos respectivamente:

INSERT INTO tabla [(columna1,

UPDATE tabla SET columna1=valor1, DELETE FROM tabla WHERE condicion

,columnan)]

VALUES (valor1,

,valorn)

,columnan=valorn

WHERE condicion

Bueno, esta sintaxis parece más sencilla que la vista en el apartado anterior. El comando INSERT no tiene ningún secreto, es muy sencilla su forma. Donde podemos encontrar algún problema es con la actualización y el borrado, problema en el sentido de entender y a posteriori determinar correctamente la condició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”,”Agapito Lafuente Corral”,”c./La plaza nueva”,”Alicante”,”03005”,”987785655”)

Insert into Clientes (“12456445”,”Maria del mar Sanchez Juan”,”c./La

marina”,”Madrid”,”25455”,”887452114)

En la segunda inserción se me ha olvidado poner los nombres de los campos de la tabla, pero no es incorrecto. Si cuando realizamos una inserción ésta afecta a todos los campos de la tabla no es necesario que indiquemos los nombre de los mismos, solamente es necesario cuando vayamos a realizar inserciones en las que algunos campos del nuevo registro no vayamos a rellenarlos, es este caso esos campos en blanco quedarán definidos con el valor NULL. Aquí hay que hacer una pequeña llamada de atención. Podemos perfectamente hacer inserciones que solamente afectan a un subconjunto de los campos de un registro y el resto dejarlo en blanco, pero tenemos que tener la precaución de nunca dejar en blanco ningún campo que hayamos 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 no tiene, al igual que las inserciones, una gran complicación. El pequeño problema, en los dos primeros, estriba en la cláusula WHERE. Los ejemplos mostrados nos enseñan como utilizar WHERE en sus posibilidades má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 la cláusula, donde conoceremos con detalle toda su potencia. No obstante voy a citar, junto con algún ejemplo má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.

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ón si 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 la tabla, 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 tablas ya 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 para relacionar cada artículo con el proveedor que lo suministra. El CIF es el identificador de un 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 tabla Factura */ Alter table LineasFactura drop constraint caj_LineasFactura1

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

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, son reglas de validación de datos. A través de una regla, vamos a definir una serie de condiciones, o podemos ver tambié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 hemos impuesto en la regla.

Las reglas que generemos se asociarán a campos de nuestras tablas. No podemos asociar una regla a una 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. La

vinculación de una regla a un campo concreto de nuestra base de datos se realiza SP_BINDRULE, y es así de fácil:

con el comando

EXEC SP_BINDRULE nombre_regla, 'tabla.campo'

El parámetro expresion del comando LIKE define el dominio correcto de los datos, es decir, define la forma o regla que tienen que cumplir los datos para poder ser aceptados y por lo tanto introducidos en el campo. 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 asignaturas solamente se imparten de lunes a viernes, situación que tendremos que controlar a la hora de introducir los datos 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'

Imaginemos una tabla Articulos de una fábrica de componentes electrónicos donde el código de los nuevos 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 la habíamos vinculado a algún campo, tendremos que desvincular la regla del campo al que esté vinculada. El comando para desvincular reglas es SP_UNBINDRULE . Si no desvinculamos antes de borrar la regla, se producirá 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

(SP_ADDTYPE, SP_DROPTYPE)

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

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

y

eliminación

de

tipos

definidos

por

el

usuario

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, como hemos 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 la vinculación, es el mismo que para desvincular una regla de un campo de una tabla, y también sufre la misma variació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 de subcontratados, y siempre este campo va a tener el mismo formato, nueve números, la mejor opción sería definirlo como tipo de usuario y asignarle una regla. De forma que cuando en cada una de las tablas generemos el campo teléfono, le asignemos este tipo de dato donde ya tenemos incorporado el formato y la regla de validación. La secuencias de instrucciones sería:

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 regla vinculada antes tendremos que romper el enlace que les une. Sería conveniente que si la regla no la vamos a asignar 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 una regla, 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 inmediatamente después de haberlo creado nos demos cuenta que está mal definido, o si el campo o campos de las tablas para 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 otro valor introducido por el usuario. Las instancias del campo tendrán por valor su valor por defecto si éste no se cambia. Cuando un campo, en la mayoría de las ocasiones, va a tener siempre un valor concreto, este valor se le puede asignar por defecto, de forma que a no ser que a la hora de la inserción de un nuevo registro o de su actualización lo cambiemos, siempre permanecerá con él.

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

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 laborales mensuales, tenemos un campo horas_trabajadas, que refleja las horas trabajadas por casa empleado al mes. A no ser que el empleado falte por algún motivo injustificado al trabajo, sus horas trabajadas mensuales son siempre las mismas, supongamos 120. Podríamos aplicarle a este campo un valor por defecto que nos evite para cada trabajador tener que estar siempre introduciendo este valor. Solamente tendremos que cambiar el valor cuando el trabajador no se ajuste a las horas normales de trabajo.

create default horas_trabajadas_120 as 120

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 los tenemos ya vinculados previamente tendremos que romper el enlace con SP_UNBINDEFAULT. ¿La sintaxis?, 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 escapa ya, 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, de momento

Bueno, ya hemos llegado casi al final. A lo largo de todo el artículo hemos conocido los fundamentos de SQL, un lenguaje soportado por todos los grandes gestores de bases de datos, que nos permite trabajar con nuestros datos con una independencia del gestor. SQL día a día se instaura más en el mercado con lo que se hace 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 dos meses, veremos como podemos trabajar con ellos. Como se que la espera es larga voy a iniciar un poco los temas que podremos conocer , espero que antes que podamos darnos cuenta, en lo que será una continuación de hasta lo aquí expuesto.

No sirve de nada que diseñemos nuestra base de datos, sus tablas, sus reglas, nuestros propios tipos de

datos, introduzcamos datos, etc

si después no vamos a manipularlos, a darles vueltas, a jugar con ellos. Uno

, de los comandos que SQL nos ofrece para divertirnos con nuestros datos es SELECT, de hecho, es uno de los más conocidos de todo el lenguaje.

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

SELECT campo1[, campo2, FROM tabla1 [, tabla2,

,campoN]

,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 campos que se encuentran en estas tablas si cumplen estas condiciones. Esta sería una forma muy llana de interpretar el 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ón modificación y borrado de datos, de este mismo artículo, donde explicamos, a grandes rasgos, el funcionamiento de la WHERE.

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

select *

from Articulos

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

select Codigo, Nombre from Articulos

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

select Codigo, Nombre, PrecioVenta from Articulos where PrecioVenta > 1000

/* El mismo caso que el anterior pero los artículos que tengan un precio de venta comprendido entre 1000 y 3000 pesetas */ select Codigo, Nombre, PrecioVenta from Articulos where PrecioVenta between 1000 and 3000

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

/* Todos los artículos cuya materia prima sea el acero o el aluminio */ select Nombre from Articulos where materia=”aluminio” or materia=”acero”

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

Ha llegado ya el momento de despedirnos, espero haber ayudado a que conozca mejor SQL, y a que se interese, si no lo estaba ya, por este mundo de las bases de datos. Le emplazo para los siguientes números de la revista Síntesis donde continuaré buceando por este océano tan grande, el Océano Bases de datos, para intentar 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.

Manipulación de datos en SQL. Las Consultas.

Óscar Javier Segura Amorós - oscarjsa@hotmail.com

Las consultas de SQL con su archiconocido SELECT, 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 la revista. Lo primero de todo y antes de proseguir, vamos a hacer un poco de memoria para recordar las bases que 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 era un lenguaje para trabajar con las bases de datos, que era un lenguaje muy difundido por su alta estandarización y que prácticamente la totalidad de los sistemas gestores de bases de datos lo trabajaban y en muchas ocasiones, sin diferencias notables en su forma. Vimos que tiene dos ámbitos de trabajo, pues podemos clasificar todas sus instrucciones dentro de dos grandes grupos: las instrucciones que trabajan con la

estructura de los datos, o lenguaje de definición de datos (LDD) y las instrucciones que trabajan con los datos en sí, o lenguaje de manipulación de datos (LMD). En el pasa artículo nos centramos solamente en el lenguaje de definición de datos, momento en el cual abordamos las instrucciones más importante dentro del grupo de definición de datos, como las instrucciones para crear las tablas, las reglas, los tipos de datos,

, siguiente 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 a empezar por el principio, centrándonos en las consultas bajo SQL dejando ya para el próximo artículo las vistas y los procedimientos almacenados. Sería un disparate, por su complejidad y extensión, pretender conocer todo el lenguaje de manipulación de datos en solamente un artículo. De esta forma, vamos a poder centrarnos en algo más concreto, las consultas, verlas con profundidad y descubrir toda la potencia que nos ofrecen.

Bueno, si nos vamos a centrar en las consultas, lo primero que nos tendremos que plantear es, ¿qué es una consulta?, ¿para qué sirve?. Preguntas totalmente fuera de lugar puesto que todos ya sabemos a estas altura que las consultas son unos procedimientos que nos van a permitir interrogar a nuestra base de datos lanzando preguntas a las tablas para obtener de esta forma los datos que nosotros necesitamos en un momento determinado. De nada sirve introducir datos en unas distribuciones de tablas si después no podemos recuperarlos, es más, ya no basta recuperar esos datos, sino que además queremos recuperar no la totalidad de los datos, solamente vamos a querer recuperar en cada momento los datos que no son necesarios. Para eso 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 nos muestre todos los datos de una tabla o de un conjunto de ellas no tiene ningún misterio. Muchas veces la complejidad la vamos a encontrar en generar esos criterios, esas condiciones que van a tener que satisfacer los datos que la consulta nos va a mostrar, los datos que nosotros queremos conocer de entre todos los que tenemos almacenados.

prometiendo una continuación al emplazaros a todos para la

insertar valores, borrarlos, modificarlos,

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

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

Junto con el artículo encontrareis varios ficheros para descargar. Estos ficheros son un apoyo, un complemento 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 ejemplos

están realizados sobre

de 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 unos datos, que por supuesto son imaginarios, datos suficientes para poder trabajar cómodamente. Además encontrareis otros ficheros con propuestas de ejercicios y sus soluciones, basados también en la en Gestión de proveedores, que servirán para poder practicar todos los apartados vistos en el artículo.

una base de datos, Gestión de proveedores , la cual podría ser un pequeño ejemplo

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

? Fichero BaseDatos.sql: Dentro de este fichero encontrareis el scrip de SQL para la creación de la base de datos de Gestión de proveedores junto con las instrucciones de inserción de los datos para que se pueda trabajar ya con ella. El scrip está optimizado para utilizarlo en SQL Server 7, lo cual no quiere decir que no vaya a funcionar en otros gestores. Si lo queremos utilizar en Interbase tendríamos que hacer dos pequeñas modificaciones: 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 que están escritas en el formato dd/mm/aaaa cambiarlas por el formato mm/dd/aaaa. Tras estas dos modificaciones podríamos correr el scrip en Interbase sin ningún problema.

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

? Fichero Soluciones.sql: Donde encontrareis las soluciones a los ejercicios propuestos en el 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)--> PIEZA Clave ajena: (numvend)--> VENDEDOR

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)--> PEDIDO Clave 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 de ellas podemos comprobar sobre el papel si los datos obtenidos con la ejecución de nuestras consultas son los datos correctos o la consulta es incompleta o errónea. ¿Qué como podemos hacer eso?, muy fácil, veamos el siguiente apartado.

No perder de vista el esquema de las tablas que se han presentado, puesto que entenderemos mejor las explicaciones 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áusulas SELECT, para indicar las columnas a mostrar y FROM para indicar la tabla en la que se encuentran dichas columnas. Su sintaxis:

SELECT [DISTINCT] Columna1, FROM Tabla

,ColumnaN

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

Si queremos mostrar la totalidad de las columnas de una tabla no es necesario enumerarlas todas dentro de 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. Si queremos mostrar toda la tabla Vendedor, podríamos comenzar por ella misma, es decir, todos sus datos, todas sus columnas:

select *

from vendedor

Al poner un * nos ahorramos el tener que escribir el nombre de todos sus campos. Esta consulta la tendrí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, sin querer mostrar la información del resto de las columnas, tendremos que seleccionar exclusivamente estos campos. Recordar que aunque la tabla seleccionada tenga más campos, solamente se mostrarán aquellos que indiquemos, seleccionemos en la cláusula SELECT:

select numvend, nomvend from vendedor

Si lo deseamos, podemos dar un nombre a las columnas que mostramos en la consulta. Para renombralas bastará con escribir el nombre que les queramos dar, entre comillas si es un nombre compuesto o si es un nombre simple directamente, después del nombre real de la columna en la sentencia SELECT. Si no lo hacemos el gestor nos mostrará el nombre real de las columnas. Interbase no soporta los renombramientos compuestos 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 la consulta, 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 nombre también se extendiera a las correspondientes tablas.

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

select distinct provincia from vendedor

Como existen varios vendedores que pertenecen a las mismas provincias, al ejecutar esta consulta obtendríamos la provincia de cada uno de los vendedores por lo que tendríamos muchos nombres de provincias que se repiten. Para evitarlo indicamos a la consulta que solamente nos muestre aquellas filas que sean 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 elegir que los resultados obtenidos se muestren de forma ascendente o descendente, basándose en los valores de unas 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 ir exactamente bajo esta cláusula, puesto que en los siguientes apartados veremos otras instrucciones que podemos 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 si indicamos varias columnas siempre se ordenarán los valores en función de la primera, y si en la primera se encuentran valores iguales, entonces las filas correspondientes a estos valores se ordenarán según la segunda columna indicada, y así sucesivamente.

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

Si no especificamos nosotros en la consulta ningún orden de listado, los datos serán mostrados en el

orden 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 forma ordenada.

select nomvend “nombre”, direccion, numvend “número vendedor” from vendedor order 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, mostrar solamente aquellos datos que cumplan unas determinadas condiciones, unos determinados criterios. Para

imponer 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 dichos

criterios por los los operadores lógicos AND y OR.

Los criterios

o condiciones se pueden especificar de muchas formas, de momento vamos a ver

solamente la forma más simple, los comparadores : <, >, <=, <=, =, <>, !=, !<, !>. En siguientes apartados utilizaremos 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 vendedor where ciudad=”Alicante”

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

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

select * from vendedor where 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 que

tengamos una cantidad disponible superior o igual a 10 unidades:

select numpieza,fecharecuento from inventario whhere cantdisponible>=10

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

Consultas con varias tablas

, normalmente

esas tablas son tablas relacionadas, es decir, unas tablas hacen referencias a las otras a través de las claves ajenas que hayamos definido en la creación de las mismas. En pocas ocasiones vamos, en una misma consulta, 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 de las tablas, separadas por comas, en la cláusula FROM.

Cuando realizamos consultas en las que vamos a utilizar varias tablas, dos, tres, cuatro,

FROM Tabla1,

,TablaN

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

FROM Tabla1, Tabla2 WHERE Tabla1.CampoComun=Tabla2.CampoComun

Veámoslo con un ejemplo. Queremos obtener todas los números de pieza y en que número de pedido se han 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 el pedido y necesitamos también la tabla Linped (Linea de pedido) puesto que en ella se encuentran las piezas que 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 se

lo indicamos a la consulta en el apartado del WHERE, además también dentro de éste apartado indicamos el

criterio de que el vendedor tiene que ser el número 1. Incluso para que queden más claros los datos mostrados, renombramos las columnas.

En el ejemplo anterior apreciamos como el dato común en las dos tablas y que sirve de enlace entre ellas es Numperido, y cada vez que hacemos referencia a él tenemos que indicar a que Numpedido nos estamos

refiriendo, 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, cuando utilizamos Numpedido le tenemos que anteponer la tabla a la que pertenece. En el caso del SELECT, la tabla

a la que pertenece Numpedido es indiferente, puesto que ya en el WHERE nos hemos ocupado de igualar

esos números de pedido. Sin embargo no ocurre así en el WHERE, donde si tenemos que hacer corresponder

Linped y por el otro

el Numpedido de la tabla Pedido.

Si no realizamos el enlace entre las tablas dentro de la consulta se produciría un producto cartesiano entre los datos de ambas tablas, relacionando así cada dato de la primera tabla con todos los datos de la segunda y por lo tanto mostrándonos un conjunto de datos que no son reales. Recomiendo que pruebes a repetir 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 última condición en el WHERE. Cuando nosotros dentro del apartado FROM indicamos que queremos trabajar con varias tablas, el gestor crea una tabla virtual, dentro del ámbito de la consulta, en la que introduce el resultado de realizar el producto cartesiano entre las tablas que nosotros le hemos indicado. Después sobre esta tabla virtual elimina las filas, los registros, que no cumplan los criterios indicados en el WHERE. Va evaluando sobre los datos de la tabla virtual los criterios por el orden en el que se encuentran escritos, de esta forma si nosotros antes de especificar el enlace hemos especifica el resto de criterios, a la hora de comprobarlos

cada número de pedido de la igualdad con su tabla, por un lado el Numpedido de la tabla

tendrá que operar con menos datos puesto que muchos de ellos ya los habrá eliminado porque no cumplían las condiciones anteriores. Entendamos que al comprobar el enlace tiene que recorrer todos los registros de la tabla comprobando la igualdad de cada registro con todos los demás, trabajo muy arduo, ayudémosle a que las comprobación sea lo más pequeña posible. Tras comprobar todos los datos con los criterios impuestos y los enlaces, 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ón BETWEEN.

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 dentro del rango que nosotros marcamos. La Expresión1 y Expresión2 será el menor valor del rango y el mayor valor del rango respectivamente. Los rangos de valores deben de ser numéricos o fechas. Fijémonos que podemos realizar selecciones inversas al poder utilizar el operador NOT.

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

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

/*Segunda forma.*/ select * from pieza where 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 pieza where preciovent<=500 or preciovent>=2000

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

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 con una 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 una forma muy sencilla, evitándonos el tener que comparar la columna con cada uno de los valores de forma independiente 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 separados

por comas, o una

irán separados por comas y además cada uno de ellos encerrado entre comillas dobles o simples.

lista de valores alfanuméricos, o fechas, en cuyos casos, cadenas alfanuméricas o fechas,

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

select * from linped where numpedido in (1,2,5)

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

select nompieza "Nombre pieza",li.numpieza "Número pieza", cantdisponible "Cantidad disponible", 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 enlaces que hemos tenido que hacer entre las diferentes tablas. Esta gran cantidad de enlaces es debido a que dos de los datos que queremos obtener están en una tabla, el tercero está en otra y la condición que se debe de cumplir está en otra diferente, por eso tanta tabla y tanto enlace. Si nos fijamos en la cláusula FROM, tras cada una de las tablas que queremos cargar hemos definido un alias, de forma que cuando queramos, en otro apartado de la consulta, hacer referencia a esa tabla lo podamos hacer de forma más cómoda utilizando el alias, es simplemente por comodidad. En la cláusula WHERE hemos puesto el criterio de la provincia lo primero de todo y después los enlaces, de esta forma optimizamos la ejecución de la consulta como ya he explicado en apartados anteriores. En la cláusula SELECT hacemos referencia al campo Numpieza, campo o columna que aparece en varias de las tablas que hemos cargado para la consulta, por lo tanto, tendremos que indicar de cuales de dichas tablas queremos que sean obtenidos los datos de dicha columna, como ya previamente habíamos enlazado las tablas es indiferente el ámbito que le asignemos. Y centrándonos ya en la parte de la consulta que se refiere a este apartado fijaros como indicado en la lista los valores que queremos encontrar, los nombre de las provincias, y como los valores son alfanumérico los hemos escrito entre comillas dobles.

Búsqueda de valores en una cadena (LIKE)

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

WHERE Columna [NOT] LIKE “Expresión”

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

? Letra y números.

? %: 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 de cadenas que nosotros buscamos.

La cláusula LIKE no se utiliza cuando buscamos una cadena en concreto, o un conjunto de cadenas determinadas que no sean parecidas, para eso utilizamos una lista de valores con la sentencia IN. LIKE la utilizaremos cuando busquemos un conjunto de cadenas en las que exista un patrón, donde podamos encontrar una expresión, utilizando los signos permitidos, que nos permita identificar a todas las cadenas del conjunto que buscamos. Dependiendo de lo fácil o complicado que sea encontrar el patrón de las cadenas que buscamos, optaremos por utilizar LIKE, si es fácil encontrar el patrón, o IN, enumerando la totalidad de las cadenas, 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 vendedor where nomvend like “Manuel %”

Nos vemos obligados a utilizar LIKE puesto que sabemos que el nombre debe de empezar por Manuel pero 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 vendedor where 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 vendedor where nomvend like “% Pérez %”

Como uno de sus apellidos es Pérez, pero desconocemos su nombre y su segundo apellido, en el caso que Pérez fuera el primero, o si es el segundo apellido, desconocemos tanto su nombre como su primer apellido, ponemos “%” tanto delante como detrás. En el caso en el que buscáramos solamente a los vendedores cuyo segundo apellido es Pérez, deberíamos de colocar un solo “%” delante del apellido, puesto que 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 pieza where 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 la potencia que LIKE nos facilita. Mucha atención a los signos utilizados y el orden de aparición.

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, al hacer esta reflexión caemos en un grave error. Un valor nulo es la ausencia de valor, es decir, cuando a una columna no se le atribuye ningún valor. Como casi todos los lenguajes existentes en la actualidad, en SQL tambié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 siguiente sintaxis:

WHERE Columna IS NULL

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

select * from pieza where descuento is null

No hay que incurrir en el error típico de hacerlo así: descuento=NULL o descuento=”NULL” puesto que de 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 de las funciones de agregado:

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

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

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

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

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

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

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

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

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

Dichas funciones agregadas retornan valores calculados sobre una determinada columna. Estas funciones devuelven un único valor para todas las tuplas seleccionadas mediante la condición de la cláusula WHERE, 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 tipo de datos numéricos.

Las expresiones pueden contener el nombre de una columna o un cálculo sobre una o varias columnas, Si se especifica la clave DISTINC, la expresión obligatoriamente ha de ser un nombre de columna, y se asume que la función se calcula únicamente sobre valores distintos de la expresión. Deberemos tener en cuenta que no 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 una instrucción SELECT, cláusula COMPUTE o COMPUTE BY y en la cláusula HAVING, la cual veremos a continuació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 linped where 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 de los 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 los datos de las columnas por las que deseemos agrupar. Las agrupaciones se realizan con la cláusula GROUP BY, la cual siempre tiene que ir situada inmediatamente detrás de WHERE, o en el caso que no existiera inmediatamente 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 la que se encuentra la columna por la que agrupamos, de forma que todas las filas que tengan el mismo valor dentro de la columna por la que agrupamos formarán parte del mismo subconjunto. Así nos encontraremos como resultado tantos subconjuntos como valores diferentes tienen los datos de la columna por la que hemos agrupado. En el caso que agrupemos por varias columnas simultáneamente la explicación anterior se amplía para varias columnas.

Un dato muy importante es que cuando utilizamos GROUP BY las columnas que aparecen en la cláusula SELECT pueden ser solamente de dos tipos: columnas agrupadas que aparecen en GROUP BY, o columnas funciones 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 con todas las líneas de todos los pedidos que se han realizado. En cada línea encontramos los datos de la pieza que 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 los siguientes datos, imaginemos, sólo por el momento, que Linped tiene esta estructura y estos datos:

Número pedido

Linea pedido

Número pieza

Cantidad pedida (cantpedida)

(numpedido)

(numlinea)

(numpieza)

1

1

AAA

20

1

2

BBB

10

Número pedido

Linea pedido

Número pieza

Cantidad pedida (cantpedida)

(numpedido)

(numlinea)

(numpieza)

1

3

CCC

15

2

1

AAA

8

2

2

HHH

10

3

1

BBB

22

3

2

PPP

10

3

3

AAA

3

Si realizamos un agrupamiento por el número del pedido nos encontraríamos con tres subgrupos: el primero formado por las filas de las tres líneas de pedido del pedido uno, el segundo subgrupo formado por las dos filas de las líneas del segundo pedido, y el tercer y último subgrupo formado por las tres filas de las líneas de 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, claramente necesitaremos utilizar COUNT (numlinea), pero si lo utilizamos sin más, es decir, sin realizar ninguna agrupación, lo que obtendremos será el número de líneas de pedido que hay en la tabla, es decir, su número de filas. Necesitamos, sin embargo, que el COUNT haga referencia a las líneas de pedido de cada pedido. Se hace necesario que realicemos una agrupación por el número de pedido y así COUNT nos devolverá el número de líneas de pedido de cada uno de los subconjuntos formados:

select numpedido, count(numlinea) from linped group by numpedido

Ya hemos logrado obtener el número de líneas de pedido que forman cada uno de los pedidos. Hemos necesitado agrupar por el número de pedido, por lo tanto, como lo tenemos en el GROUP BY estamos obligados a ponerlo también en el SELECT. Si intentamos mostrar cualquier otra columna de la tabla Linped veremos 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 100 pedidos 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 linped where numpedido<=100 group by numpieza order by numpieza

En esta ocasión no hemos tenido que agrupar por el número de pedido, es un dato que nos nos importa ahora, sino que hemos tenido que agrupar por el número de la pieza. Y para obtener la cantidad que se ha pedido 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 pieza para 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 que vamos a mostrar en la consulta, de forma que solamente aquellas filas que cumplan las condiciones marcadas en el WHERE serán mostradas. Los grupos también tienen su propia cláusula para imponer condiciones, la cláusula HAVING. Con HAVING vamos a indicar las condiciones que tienen que cumplir los grupos formados por GROUP BY para que puedan ser mostrados en el resultado de la consulta. HAVING simpre estará situado inmediatamente detrás de GROUP BY. Su sintaxis es:

HAVING Condición1,

,CondiciónN

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

select numpedido, count(numlinea) from linped group by numpedido having min(cantpedida)>5

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

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

Es la misma consulta que ya habíamos realizado anteriormente sólo que ahora imponemos una condición al subconjunto, y es que exista más de una fila. Si existe más de una fila significa que esa pieza se ha pedido más de una vez, puesto que estamos agrupando por la pieza, por su número, los subgrupos tendrán tantas filas como veces aparezca esa pieza en la tabla de líneas de pedido, o lo que es lo mismo, el subconjunto tendrá 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. Hemos hecho un recorrido amplio por las consultas en SQL, nos han presentado al famoso por excelencia del lenguaje de consultas estándar, SELECT, y de paso, a unos cuantos amigos suyos sin los cuales no podría hacer nada.

Tenemos en nuestras manos las herramientas suficientes para satisfacer la mayoría de los interrogantes que le podemos plantear a los datos de nuestras tablas. Ahora solamente nos resta jugar con estas herramientas 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 juegos que antes comentábamos. El primero, con la base de datos que nos ha servido de ejemplo durante todo el artículo y sobre la que hemos basado muchas de las explicaciones, y los otros dos con propuestas de consultas que abarcan todos los apartados que hemos tratado y sus correspondientes soluciones. Como se suele hacer en estos casos, recomendaros que primero intentéis resolver vosotros solos los problemas que se os plantean y después miréis las soluciones, y como siempre, lo haréis al revés, pero en fin, yo también lo haría.

En el próximo número continuaremos con SQL embarcándonos esta vez en las consultas anidadas, que se trata de pasarle a una consulta el resultado de otra consulta y que estos datos devueltos por la primera de todas, la subconsulta, sirva a la segunda para satisfacer una serie de condiciones impuestas. Además conoceremos 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áis mejor 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.

SQL. Vistas y procedimientos.

Óscar Javier Segura Amorós oscarjsa@hotmail.com

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

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

Hoy vamos a conocer las vistas y los procedimientos almacenados, intentaremos dar una visión amplia de para 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 a aportar 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 ataca desde 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 el gestor de la base de datos en el servidor. No es muy correcto obtener todos los datos del servidor, pasarlos a la aplicación y una vez que los tenemos ya en la aplicación analizarlos, tratarlos y quedarnos solamente con los necesarios, con esta política estamos produciendo una sobrecarga en la red o en el canal de transferencia de datos utilizado y además estamos relentizando el funcionamiento de nuestra aplicación. Hay que intentar distribuir el trabajo entre los diferentes elementos que conforman nuestro sistema informático, haciendo que cada 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 atender nuestras peticiones de información, sino también para desahogar el funcionamiento de los clientes, y eso lo tenemos 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 podemos eliminar cierta programación del cliente y situarla sobre el servidor, optimizando así nuestro trabajo y consiguiendo una aplicación más rápida, y más fácil de mantener y acturalizar. Programación referida no solamente 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 a conformar en lo que podríamos denominar una tabla virtual; tabla , porque vamos a poder trabajar con esos datos como si pertenecieran a una tabla más de nuestra base de datos, pudiendo sobre ellos realizar inserciones, borrados, actualizaciones, incluso consultas, y virtual porque en realidad no es una tabla propiamente dicha de nuestra base de datos aunque podamos trabajar con ella como tal.

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

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

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

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

? Agregar información en lugar de presentar los detalles. Por ejemplo, presentar la suma de una columna, 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 puedan ejecutar de forma rápida, evitando de esta forma, que tengan que teclear cada días las mismas consultas 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 ya existentes de forma que solamente se pueda trabajar con un subconjunto definido de los datos. Por ejemplo que el personal del departamento de publicidad solamente pueda trabajar con los datos de aquellos 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 o columnas de nuestra base de datos y después asignar a cada usuario permisos para poder utilizar determinadas vistas. De esta forma estamos ofreciendo a cada tipo de usuario acceso exclusivamente a los datos que les hacen falta evitando de así que un usuario pueda ver o trabajar con 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, AS SELECT expresión

FROM tabla1,

, columnaN)]

, [WHERE expresión] [GROUP BY [ALL] expresión1, [HAVING condición] [WITH CHECK OPTION]

tablaN, vista1,

, vistaN

, expresiónN]

Una vez que hemos creado la vista, los datos que la consulta devuelve se convierten en una tabla, como anteriormente explicaba, cuyo nombre es el nombre que le hemos asignado a la vista y por lo tanto podemos hacer referencia a ella utilizando el nombre de la misma. Por ejemplo, si quisiéramos ver todos los datos que devuelve la vista, simplemente tenemos que hacer una consulta, y dicha consulta la hacemos como si la hicié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.

? El nombre de la vista debe de cumplir las reglas de los identificadores. Especificar el nombre del propietario 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 una expresión aritmética, una función o una constante, cuando dos o más columnas pueden tener el mismo nombre, debido normalmente a una combinación, o cuando la columna de la vista recibe un nombre distinto al de la columna de la que se deriva. Los nombre de las columna las podemos asignar también en la consulta, tras la cláusula SELECT como se hace en las consultas, sin nos resulta más sencillo.

Si no especificamos ningún nombre a las columnas, estas adquirirán el nombre de la columna de la que 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, con una tabla o con varias, podemos trabajar también con otras vistas utilizándolas como simples tablas, las únicas restricciones que tenemos, las únicas cosas que no podemos utilizar en las consultas que definen una vista es la utilización de las cláusulas ORDER BY, COMPUTE o COMPUTE 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 de datos ejecutadas contra la vista cumplan los criterios establecidos en el apartado SELECT. Si nosotros estipulamos en la consulta una serie de condiciones, en el futuro, a la hora de realizar alguna actualización de los datos, bien sea modificándolos o insertando datos nuevos, no podremos llevarla 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 que controlamos sobre que subdominios de datos del dominio original de la tabla el usuario puede trabajar.

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 exclusivamente

a las cuentas de grandes clientes y otro dedicado a las cuentas de clientes pequeños y medianos, la

clasificación se establece en función del volumen de compra anual que dichos clientes nos realizan. Para que cada uno de los administrativos tenga acceso solamente a los datos de los clientes con los que tienen que

trabajar, una solución, es crear dos vistas, una

a una cierta cantidad y la otra vista trabajará con el resto de clientes. De esta forma no tenemos que crear

dos tablas de clientes diferentes, la estructura de la base de datos no se tiene que modificar. Si un día el administrativo 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 el segundo administrativo de alta al nuevo cliente y quiera comprobar sus datos, éste no le aparecerá por ningún sitio, y si intenta volver a darle de alta, el sistema le dirá que ya existe, ¡para volverse loco!, pensará, y como siempre terminará culpando al informático. ¿Qué ha ocurrido?, el alta del nuevo cliente se ha realizado sin ningún problema, ya está introducido en la base de datos, pero como el administrativo trabaja con la tabla de clientes a través de una vista, y esta le muestra solamente un subconjunto de los datos, a él le parece que no ha conseguido introducir al nuevo cliente. Veamos cuales podrían ser las vistas de esta situación.

vista trabajará con los clientes cuya compra anual sea superior

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),

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

)

CREATE VIEW VISTA_CLIENTES_GRANDES AS SELECT * FROM CLIENTES WHERE COMPRA_ANUAL >= 10000000

CREATE VIEW VISTA_CLIENTES_PEQUEÑOS AS SELECT * FROM CLIENTES WHERE COMPRA_ANUAL < 10000000

Para evitar la situación que he descrito podríamos haber utilizado el argumento WITH CHECK OPTION. Si creamos las vista utilizando este argumento, estamos obligando a que en el futuro cuando queramos realizar una modificación o una inserción, éstas van a tener que cumplir los criterios establecidos en la vista. En el ejemplo concreto, si la hubiéramos utilizado, el administrativo al intentar dar de alta al cliente no hubiera podido, puesto que el administrativo va a realizar la inserción contra la vista de clientes pequeños por lo que el cliente no va a satisfacer la condición impuesta en el campo de COMPRA_ANUAL. Como no se había establecido el argumento de chequeo, la inserción se puede realizar perfectamente, pero a la hora de comprobar los datos, el nuevo dato no aparecerá, no porque no exista, sino porque la vista no lo tiene que mostrar. En nuestro caso, cuando el administrativo de los clientes grandes se vuelva a incorporar al trabajo y ejecute 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 al final 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 tan sencilla 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 estaba relacionada permanecen intactas y podemos continuar utilizándolas sin ningún problema. No sucede lo mismo si lo que hacemos es borrar una tabla o vista que era utilizada por otra vista. Cuando se da esta situación nos pueden 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 que alguna de las tablas que se utilizan en la vista ya no están disponibles, por lo que no podremos trabajar 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 la tabla, podremos volver a utilizar la vista sin ningún problema. Aquí solamente hay que tener la precaución de crear la tabla con el mismo nombre y como mínimo, con los mismos campos que se utilizan en la vista.

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

asociado a ésta, tendremos tabla.

previamente que borrar la vista, para a continuación poder borrar la

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

Continuando

con

el

ejemplo

del

apartado

anterior,

podríamos

borrar

las

dos

vistas

incluso

simultá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 que admitiese 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 de programació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, incluidas las llamadas a otros procedimientos.

? Devolver un valor de estado para indicar si la operación se ha realizado correctamente o ha habido 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 sus anchas con las instrucciones de actualización, UPDATE, INSERT y DELETE, corremos el riesgo que no siempre se cumplan las reglas de consistencia. Una forma de evitarlo es trabajando las actualizaciones a través de procedimientos, puesto que tenemos un control de cómo se va a realizar ese proceso.

? Reducen el tráfico en la red. Los procedimientos se ejecutan en el servidor por lo que no tenemos que recibir tablas enteras de datos para realizar después nuestros análisis, el análisis de los datos se 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 varias aplicaciones trabajen con la misma base de datos Si programamos en la propia base de datos las reglas de consistencia nos ahorramos tener que repetir la misma programación en las distintas aplicaciones, 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ás fácil, llegado el momento, cambiar la programación del procedimiento que cambiar la programació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 su creación y después podemos utilizarlo ya directamente tantas veces como queramos. Si por el contrario utilizamos lotes de comandos de SQL, cada vez que los utilizamos se tienen que compilar y optimizar.

Creación de procedimientos (CREATE PROCEDURE)

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

Para SQL Server

CREATE PROCEDURE nombre_procedimiento

[@variable1 tipoDato, AS Instrucciones SQL

, @variableN tipoDato [OUTPUT]]

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; ] BEGIN Instrucciones SQL END

El nombre_procedimiento es el nombre del nuevo procedimiento almacenado, utilizaremos este nombre cada vez que queramos referirnos a él, bien sea para ejecutarlo o para borrarlo. Los nombre de procedimientos 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 podemos declarar una o varias variables y cuando ejecutamos el procedimiento el usuario debe de asignar los valores correspondientes a dichas variables y en el orden en las que estas han sido declaradas. En SQL Server el nombre de las variables siempre empieza por el signo @, no siendo así en Interbase. Las variables son locales al 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áusula OUTPUT al lado de la variable que queremos que retorne su valor, y en Interbase, este tipo de variables deben de declararse separadas de las variables de entrada y después de la cláusula RETURNS. Salvo las diferencias 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 de instrucciones SQL.

Instrucciones SQL son las instrucciones de SQL que se incluirán en el procedimiento. Aquí existe alguna limitación, no todas las cláusulas de SQL tienen cabida aquí, depende de cada gestor de bases de datos 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ámetro como NULL y ese parámetro se utiliza en una instrucción CREATE o ALTER TABLE que hacer referencia a una columna que no admite valores NULL, se generará un error.

Principales instrucciones SQL permitidas en los procedimientos

A continuación vamos a comentar las principales instrucciones de SQL que son soportadas en los procedimientos. Como ya hemos podido comprobar anteriormente en la creación del procedimiento, pueden existir diferencias entre los distintos gestores de bases de datos, yo voy a centrarme en Interbase, aunque las diferencias 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 en la creación del procedimiento.

Variable = Expresion

? Llamadas a procedimientos, con la parámetros

precaución

de que no se admiten expresiones en los

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. Estas instrucciones pueden utilizar variables locales y parámetros, siempre que éstas estén precedidas de dos puntos “:”, para que se puedan diferenciar las variables y parámetros de los nombres de columnas.

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

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

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

? Iteración sobre consultas. Recorremos el conjunto de filas definido por la instrucción select . Para cada fila, transfiere los valores a las variables de la cláusula into, de forma similar a lo que sucede con 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. La instrucción suspend , se utiliza con procedimientos que devuelven un conjunto de filas a la rutina que lo ha llamado, suspende temporalmente el procedimiento, hasta que la rutina que lo llama haya procesado los valores retornados.

exit;

suspend;

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ón los valores que queremos darle a los parámetros. Recordar que los valores de los parámetros tienen que pasarse al procedimiento en el mismo orden en el que han sido definidos en el momento de la creación del mismo.

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 es necesario que utilicemos un carácter de terminación para que la aplicación que vayamos a utilizar para tal fin sepa diferenciar cuando termina un bloque de instrucciones y comienza otro. El carácter de terminación lo establecemos 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 tenemos que introducir los bloques de instrucciones SQL, por lo que aparecerán caracteres de terminación que pertenecen a los diferentes apartados del bloque de instrucciones pero no indican que ha terminado el procedimiento. Sin embargo la aplicación que utilicemos para introducir el script tomará estos terminadores como marcas de que ha terminado el procedimiento almacenado. Este es el motivo de tener que cambiar el cará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 ponerle el punto y coma “;”, señal de que termina. De ahora en adelante, hasta que lo volvamos a cambiar, cada instrucción que escribamos irá finalizada por “^”. Para reponer todo a su sitio y dejarlo como ha sido siempre tendremos 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 idea de la distribución del trabajo que apuntaba en la introducción del artículo, y que al igual que yo,penséis que

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

Un saludo y hasta pronto.

Óscar J. Segura Amorós

oscarjsa@hotmail.com