EL ESTANDAR ANSI SQL (86) 1. INTRODUCCIÓN

Anuncio
Dpto. de Organización y Estructura de la Información (EUI-UPM)
Asignatura de Bases de Datos
Pedro Pablo Alarcón Cavero
Diciembre 1994
EL ESTANDAR ANSI SQL (86)
INDICE
1. INTRODUCCION.
2. LENGUAJE DE DEFINICION DE DATOS
3. LENGUAJE DE MANIPULACION DE DATOS
3.1. OPERACIONES DE ACTUALIZACION
3.2. OPERACIONES DE CONSULTA O RECUPERACION
4. LENGUAJE DE CONTROL DE DATOS
5. SQL INMERSO.
6. EJEMPLOS.
1. INTRODUCCIÓN
Desde que el Dr. Codd introdujera el concepto de Base de Datos Relacional, hacia 1970, hasta que se diseño un SGBDR
(System R) pasaron varios años. El System R (diseñado por IBM), no era más que un prototipo, y el principal objetivo era que el sistema
fuese operacionalmente completo, es decir, demostrar que era posible construir un Sistema Relacional, utilizable en un entorno real, para
solucionar problemas verdaderos, con un desempeño al menos comparable al de los sistemas existentes. Este sistema incorporaba un
sublenguaje de datos que permitía realizar cualquier acceso a la Base de Datos, que se llamó SEQUEL. Posteriormente otros sistemas
adoptaron este sublenguaje, al que pasaron a llamar SQL, como sublenguaje de consulta de datos, realizando modificaciones sobre él,
hasta hoy en día, en que su utilización dentro del ámbito comercial es realmente extensa.
SQL es una abreviatura de "Structured Query Language", esto es, Lenguaje de Consulta Estructurado. Con este lenguaje se
formulan operaciones relacionales, es decir, operaciones que permiten definir y manipular una base de datos relacional.
En 1986, el Instituto Nacional Norteamericano de Normalización (ANSI) publicó las primeras normas que enunciaban la
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 1
sintaxis y la semántica de SQL. En 1989, ANSI definió el SQL2, basado en el anterior pero con una serie de mejoras (definición de claves
primarias, integridad de los datos, etc.).
En este tema, abordaremos el estudio del SQL 86, ya que es en éste en el que está basado la versión de Informix_SQL que
se utilizará para desarrollar las prácticas de la asignatura.
A lo largo de la exposición se hace referencia en los ejemplos a distintas tablas. Estas tablas se encuentran en el apartado 6
correspondiente a los ejemplos (página 18).
1.1. ARQUITECTURA
En la figura siguiente se muestra como ven los usuarios el SGBDR, bajo el punto de vista de la arquitectura de bases de datos
ANSI/X3/SPARC.
SQL
NIVEL
EXTERNO
NIVEL
CONCEPTUAL
NIVEL
INTERNO
Nivel Externo:
VISTA 1
...
VISTA N
TABLA
BASE 1
TABLA
BASE 2
...
TABLA
BASE N
FICHERO
FÍSICO 1
FICHERO
FÍSICO 2
...
FICHERO
FÍSICO N
lo componen las vistas y tablas base.
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 2
Nivel Conceptual: compuesto por tablas base.
Nivel Interno:
compuesto por ficheros físicos. Las tablas base están almacenadas en ficheros, donde cada fila corresponde
a un registro del fichero. Incorpora la posibilidad de construir índices sobre cada una de las tablas.
Por tanto, las tablas que los usuarios pueden manejar son de dos tipos: tablas base y vistas.
•
Una tabla base, es una tabla que tiene existencia por sí misma, es decir, sus filas (registros) se encuentran almacenados
físicamente en uno o varios ficheros físicos.
•
Una vista es una tabla virtual, esto es, no tiene existencia por sí misma, se definen a partir de una o más tablas base. De
ellas solamente existe su definición en el diccionario de datos, y cuando se opera con ellas, se opera en realidad con las
tablas base sobre las que está definida.
CATALOGO: Los SGBDR tienen una base de datos propia del sistema, que se llama catálogo o diccionario de datos y que contiene
el esquema de las bases de datos de usuario, es decir, contiene información sobre las tablas base, las vistas, índices,
los derechos de acceso, identificación de usuarios, etc. El catálogo no es propio del lenguaje SQL, sino de cada
sistema en particular, pero puede consultarse utilizando la instrucción SELECT de SQL.
1.2. ENTORNO DE UTILIZACIÓN
Una característica importante de SQL es que puede utilizarse a través de dos interfaces diferentes, un interface interactivo y
un interface para programas de aplicación.
a) Interactivo:
SELECT LOCALIDAD
FROM PROYECTO
WHERE P# = 'P3’;
El usuario teclea la proposición SELECT (consulta) en un terminal, y el sistema responde con la presentación del resultado
en ese terminal.
b) Embebido en un lenguaje de programación (Pascal, Cobol, C,...)
EXEC SQL SELECT LOCALIDAD
INTO :MLOCALIDAD
FROM PROYECTO
WHERE P# = 'P3’;
Este ejemplo, muestra la misma proposición SELECT en esencia, embebida en un programa de aplicación (en el ejemplo
Pascal). En este caso, la proposición se ejecutará cuando se ejecute el programa, y el resultado se devolverá no a un
terminal, sino a la variable de programa MLOCALIDAD.
También se incluyen en este grupo, los lenguajes de cuarta generación (4gl), que son lenguajes orientados a la gestión de
bases de datos, y suelen ir incorporados con el SGBDR. Permiten programar aplicaciones para gestionar una base de
datos utilizando sentencias SQL y las sentencias propias del lenguaje.
Así pues, el SQL es al mismo tiempo un lenguaje de consulta interactivo y un lenguaje de programación de bases de datos,
aunque difieren en ciertos detalles que se verán más adelante.
En función de esta característica, existirán dos tipos de usuarios en el sistema, usuarios finales en terminales en línea y
programadores de aplicaciones (el SGBDR deberá permitir el acceso concurrente a datos compartidos, por parte de múltiples usuarios
(finales y programas de aplicación) de los dos tipos, realizando los controles necesarios para mantener la integridad y seguridad de los
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 3
datos).
Por último, indicar que las sentencias SQL deben terminar en punto y coma (;), y que existe total libertad para escribir las
palabras que componen una sentencia.
1.3. FUNCIONES DE SQL
Aún cuando se describe a SQL como un lenguaje de consulta, en realidad es mucho más que eso, ya que dispone de otras
funciones además de las de consultar una Base de Datos. Entre éstas se incluyen las relativas a:
- definición de datos.
- manipulación de los datos de la Base de Datos.
- especificar restricciones de acceso y seguridad.
Cada función tiene su conjunto propio de instrucciones, que se expresan respectivamente en:
- Lenguaje de Definición de Datos (LDD)
- Lenguaje de Manipulación de Datos (LMD)
- Lenguaje de Control de Datos (LCD)
2. LENGUAJE DE DEFINICIÓN DE DATOS
El lenguaje de definición de datos (LDD) tiene como principales funciones:
- Crear, suprimir o modificar la definición de una tabla.
- Definir y suprimir una vista de datos (tabla virtual).
- Definir y suprimir índices de tablas.
Estas funciones permiten definir y modificar el esquema de una base de datos y por tanto provocarán una modificación del
catálogo del sistema, que contiene el esquema de la base de datos.
Los tipos de datos que contempla SQL estándar son:
•
Cadenas de caracteres:
CHARACTER (long)
•
Numérico exacto o entero
•
INTEGER o INT
SMALLINT (entero corto)
NUMERIC (precisión, escala)
DECIMAL (precisión, escala)
Numérico aproximado o de coma flotante:
FLOAT (precisión)
REAL
DOUBLE PRECISION
2.1. SENTENCIAS SOBRE TABLAS
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 4
§
Creación de tablas
CREATE TABLE nombre_tabla
(<definición_atributo_1> [UNIQUE] [NOT NULL],
(<definición_atributo_2> [UNIQUE] [NOT NULL],
.....................
(<definición_atributo_n> [UNIQUE] [NOT NULL]);
donde:
definición_atributo = nombre_atributo tipo_dato (tamaño)
UNIQUE: no se permiten valores duplicados en la columna
NOT NULL: no se permiten valores nulos en la columna
•
Modificación de tablas
-
Añadir un nuevo atributo
ALTER TABLE <nombre_tabla>
ADD <definición_atributo>;
En el caso que la tabla contenga una serie de filas, no se podrá definir el atributo nuevo ni como UNIQUE ni
como NOT NULL (ya que en las filas existentes no tendrá valor).
-
Modificar un atributo ya existente
ALTER TABLE <nombre_tabla>
MODIFY <definicion_atributo>
Si la tabla ya contiene filas, se podrá poner el atributo como NOT NULL, si dicho atributo no tiene valor nulo en
ninguna fila. Si se quiere definir como UNIQUE el atributo no puede tener valores duplicados en las filas existentes.
•
Eliminación de tablas
DROP TABLE <nombre_tabla>
Esta sentencia elimina tanto el contenido como la definición (esquema) de la tabla especificada.
2.2. SENTENCIAS SOBRE VISTAS
•
Creación de vistas
CREATE VIEW <nombre_vista> (<lista_atributos>)
AS ( <clausula SELECT> )
Permite definir una vista de usuario (tabla virtual) a partir de las tablas existentes en la base de datos. Las filas de
la vista serán aquellas que resulten de ejecutar la consulta sobre la que está definida. La consulta se especifica
mediante la cláusula SELECT que se verá posteriormente.
•
Eliminación de vistas
DROP VIEW <nombre_vista>;
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 5
Esta sentencia permite eliminar la definición de una vista de usuario del catálogo de la base de datos.
2.3. SENTENCIAS SOBRE INDICES
•
Creación de índices
CREATE [UNIQUE] INDEX <nombre_indice>
ON <nombre_tabla> (<lista_atributos>);
Esta sentencia crea un fichero índice para la tabla y atributos especificados. Este fichero tendrá las filas de la tabla ordenadas
según los valores de los atributos (clave del índice), de manera que permita el acceso directo a las filas de la tabla.
La opción UNIQUE, determina que no puede haber valores duplicados en la clave del índice.
•
Eliminación de índices
DROP INDEX <nombre_indice>
[ON <nombre_tabla>]
Esta sentencia elimina el fichero índice especificado. La opción "ON nombre_tabla", cuando más de una tabla tenga índices
con el mismo nombre.
Es el sistema el encargado de utilizar los índices, para optimizar el acceso a los datos. El usuario sólo puede crear o eliminar
índices, pero no indicar su utilización.
3. LENGUAJE DE MANIPULACION DE DATOS
Se distinguen dos tipos de operaciones:
•
Operaciones de actualización (Actúan sobre una única tabla)
INSERT : inserción de filas
DELETE : eliminación de filas
UPDATE : modificación de filas
•
Operaciones de consulta (Actúan sobre varias tablas)
SELECT : consulta sobre la Base de Datos
3.1. OPERACIONES DE ACTUALIZACION
3.1.1. INSERCIÓN DE FILAS
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 6
•
Inserción de una fila
INSERT
INTO <nombre_tabla> [(<lista_de _atributos>)]
VALUES (<valor_1>, <valor_2>,...,<valor_n>);
Los atributos que no aparezcan en lista_de_atributos quedarán con valor NULL (también puede aparecer en VALUES el
valor NULL). Es obligatorio especificar un valor para los atributos que estén definidos como "NOT NULL".
•
Inserción de varias filas
INSERT
INTO <nombre_tabla> [(<lista_de_atributos>)]
( <clausula SELECT> )
Los atributos de ambas listas de atributos deben coincidir en el mismo dominio. La cláusula "SELECT" especifica una
consulta cuyo resultado (filas) se insertará en la tabla especificada.
3.1.2. MODIFICACIÓN DE FILAS
UPDATE <nombre_tabla>
SET <atributo_1> = <valor_1>,
<atributo_2> = <valor_2>,
...........
<atributo_n> = <valor_n>
[WHERE <condición>];
La modificación afectará a todas las filas que cumplan la condición, si se especifica ésta (la cláusula WHERE expresa la
condición de búsqueda en una consulta y se verá posteriormente). Si no se especifica condición, la modificación afectará
a todas las filas de la tabla. El valor que se asigne a un atributo puede ser una constante, o el resultado de una subconsulta
(que deberá ir entre paréntesis).
3.1.3. ELIMINACION DE FILAS
DELETE
FROM <nombre_tabla>
[WHERE <condición>];
No se pueden eliminar partes de una fila. Si no aparece la cláusula "WHERE" se eliminarán todas las filas de la tabla, no
eliminándose la definición de ésta en el esquema.
3.2. OPERACIONES DE CONSULTA
3.2.1. SINTAXIS DE LA SENTENCIA
SELECT [UNIQUE/DISTINCT] <expresión>
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 7
FROM <lista_de_tablas>
[WHERE <condicion>]
[GROUP BY <lista_de_atributos>
[HAVING <condición_de_grupo> ]]
[ORDER BY <lista_de_atributos> [ASC/DESC] ];
SELECT: Indica que la operación a realizar es una consulta, y además qué información se desea obtener. Se puede incluir
la opción UNIQUE o DISTINCT para no obtener filas duplicadas en el resultado.
FROM:
Especifica las tablas en las que se encuentran los atributos implicados en la consulta.
WHERE: Especifica la condición de búsqueda que se requiere para obtener la información deseada.
GROUP BY: Permite agrupar el resultado en base a los atributos especificados.
HAVING:
Especifica una condición de grupo.
ORDER BY: Permite ordenar el resultado en base a los atributos especificados
3.2.2. OPERADORES
Los siguientes operadores se pueden utilizar para expresar condiciones de fila (cláusula WHERE) o de grupo (cláusula
HAVING).
- De comparación (<, <=, >, >=, <>, =)
- Lógicos (AND, OR, NOT)
- BETWEEN ... AND ...
- LIKE
- IN
- IS NULL
- Cuantificadores (ANY, SOME, ALL)
- Existencial (EXISTS)
3.2.3. CONDICIONES DE SELECCIÓN
1. Recuperación simple
Ø
Obtener todos los datos de todos los proyectos.
SELECT p#, descrip, localidad, cliente
FROM proyecto
ó:
SELECT *
FROM proyecto;
*: equivale a todos los atributos de una tabla
Ø
Obtener los códigos de máquina (m#) para todas las máquinas utilizadas.
SELECT DISTINCT m#
FROM trabajos;
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 8
2. Recuperación calificada
Ø
Obtener los códigos de los conductores que son de Arganda.
SELECT c#
FROM conductores
WHERE localidad = 'ARGANDA';
Ø
Obtener los códigos de los conductores de Arganda que tengan categoría inferior a 20.
SELECT c#
FROM conductores
WHERE localidad = 'ARGANDA' AND categ < 20;
3. Recuperación con más de una tabla.
Ø
Obtener para cada máquina utilizada, el código de máquina y el nombre.
SELECT DISTINCT trabajos.m#, nombre
FROM trabajos, maquinas
WHERE trabajos.m# = maquinas.m#;
En la condición de la consulta hemos especificado la unión natural entre las tablas trabajos y máquinas. Cuando un
atributo tiene el mismo nombre en más de una tabla de las especificadas en la cláusula FROM es necesario expresar
el atributo precediéndolo del nombre de la tabla y un punto.
4. Recuperación con el operador 'BETWEEN ... AND ...'
Establece una comparación dentro de un intervalo.
Ø
Obtener el nombre de máquina para aquellas cuyo precio por hora esté comprendido entre 5000 y 15000
ptas.
SELECT nombre
FROM maquinas
WHERE precio_hora BETWEEN 5000 AND 10000;
También se puede utilizar NOT BETWEEN.
5. Recuperación con el operador 'LIKE'.
Establece una comparación entre cadenas de caracteres, empleando los siguientes comodines:
Ø
'%' : sustituye a una cadena de caracteres cualquiera.
'_' : sustituye a un carácter cualquiera.
Obtener los nombres de aquellos trabajadores que comiencen por 'C'.
SELECT nombre
FROM conductores
WHERE nombre LIKE "C%";
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 9
También se puede utilizar NOT LIKE.
6. Recuperación con el operador "IN".
Indica pertenencia. Comprueba la pertenencia de una valor a un conjunto dado (que debe ir entre
paréntesis). Este conjunto puede especificarse por enumeración de sus elementos o por el resultado de la
ejecución de una sentencia SELECT.
Ø
Obtener los nombres de aquellos conductores que residen en Arganda o en Rivas.
SELECT nombre
FROM conductores
WHERE localidad IN ('ARGANDA','RIVAS');
Ø
Obtener nombres de los trabajadores que han utilizado la máquina 'M2'.
SELECT nombre
FROM conductores
WHERE c# IN (SELECT c#
FROM trabajos
WHERE m# = 'M2');
ó:
SELECT nombre
FROM conductores, trabajos
WHERE conductores.c# = trabajos.c# AND m# = 'M2';
ó:
SELECT nombre
FROM conductores
WHERE 'M2' IN (SELECT m#
FROM trabajos
WHERE conductores.c# = trabajos.c#);
También se puede utilizar NOT IN.
7. Recuperación con el operador 'IS NULL'.
Comprueba si un valor determinado es nulo (NULL).
Ø
Obtener los partes de trabajo que no figuren con el tiempo empleado.
SELECT c#, m#, p#, fecha
FROM trabajos
WHERE tiempo IS NULL;
También se puede utilizar IS NOT NULL.
8. Recuperación con cuantificadores (ALL, ANY).
ALL: todos, ANY: alguno. Van acompañados de un operador de comparación:
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 10
Ø
-
ALL
>= ALL
< ALL, ...
-
ANY
>= ANY
< ANY, ...
Obtener los conductores que no han participado en el proyecto 'P1'.
SELECT nombre
FROM conductor
WHERE c# <> ALL (SELECT c#
FROM trabajos
WHERE p# = 'P1');
Ø
Obtener los trabajadores con categoría inferior a la de algún trabajador de Arganda.
SELECT nombre
FROM conductores
WHERE categ < ANY (SELECT categ
FROM conductores
WHERE localidad = "ARGANDA");
9. Recuperación con el operador 'EXISTS'.
Indica la existencia o no de un conjunto. Va asociado a una subconsulta.
Ø
Obtener nombres de las máquinas que se han utilizado en el proyecto P3.
SELECT nombre
FROM maquinas
WHERE EXISTS (SELECT *
FROM trabajos
WHERE trabajos.m# = maquinas.m# AND p# = 'P3');
3.2.4. OTROS OPERADORES
1. Recuperación con UNION Y DIFERENCIA
Unión de conjuntos: operador UNION
Diferencia de conjuntos: operador MINUS
Ø
Obtener los códigos de aquellos conductores que residan en Rivas o tengan categoría inferior a 15.
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 11
SELECT c#
FROM conductores
WHERE localidad = 'RIVAS'
UNION
SELECT c#
FROM conductores
WHERE categ < 25;
Ø
Obtener los códigos de aquellos trabajadores que tengan categoría inferior a 15 y que no hayan trabajado
con la máquina M3.
SELECT c#
FROM conductores
WHERE categ < 15
MINUS
SELECT c#
FROM trabajos
WHERE m# = 'M3';
2. Expresiones en la cláusula SELECT
No sólo se pueden seleccionar atributos, sino expresiones en las que aparezcan atributos y/o constantes y operadores
aritméticos (+, -, *, /).
SELECT nombre, 'coste final por hora:', (precio_hora*1.15)
FROM maquinas;
3.2.5. FUNCIONES AGREGADAS
•
COUNT (*): contador de tuplas (totalizador)
•
COUNT (DISTINCT): contador de tuplas (parcial), no tiene en cuenta valores nulos ni duplicados
•
AVG: media aritmética de un atributo o una expresión numérica
•
SUM: suma de atributos o expresiones numéricas
•
MAX: valor máximo de un atributo o expresión numérica
•
MIN: valor mínimo de un atributo o expresión numérica
Devuelven un valor único, numérico, como resumen de la información relativa a atributos. No se puede combinar una función
agregada, con columnas que devuelvan más de un valor, a menos que la consulta contenga una cláusula GROUP BY.
Ø
Obtener el número total de proyectos realizados
SELECT COUNT(*)
FROM proyectos;
Ø
Obtener el número total de máquinas que se han utilizado en 'P2'.
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 12
SELECT COUNT (DISTINCT m#)
FROM trabajos
WHERE p# = 'P2';
Ø
Obtener el precio medio por hora de las máquinas utilizadas en el proyecto 'P1'
SELECT AVG(precio_hora)
FROM maquinas
WHERE m# IN (SELECT m# FROM trabajos WHERE p#='P1');
Ø
Obtener el precio total a pagar a los trabajadores del proyecto 'P3'
SELECT SUM (tiempo*precio_hora)
FROM trabajos, maquinas
WHERE p# = 'P3' AND trabajos.m# = maquinas.m#;
Ø
Obtener el precio hora de máquina más elevado"
SELECT MAX (precio_hora)
FROM maquinas;
Ø
Obtener el nombre del conductor que ha trabajado menos tiempo con la máquina 'M2'.
SELECT nombre
FROM conductores
WHERE c# IN (SELECT c# FROM trabajos
WHERE tiempo IN (SELECT MIN(tiempo) FROM trabajos
WHERE m# = 'M2'));
3.2.6. CLAÚSULA GROUP BY
GROUP BY <lista_de_atributos>
Agrupa el resultado de una consulta en base a uno o varios atributos, devolviendo una única fila por grupo. El agrupamiento
no se realiza ordenado, el resultado de éste depende de como esté la tabla. Los atributos que aparezcan en la cláusula GROUP
BY, deben aparecer en la cláusula SELECT.
Ø
Obtener por cada conductor que haya trabajado, el código de éste y la cantidad total de tiempo empleado.
SELECT c#, SUM(tiempo)
FROM trabajos
GROUP BY c#;
Resultado:
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 13
c# SUM(tiempo)
C2
C3
C5
C4
C1
210
500
240
90
420
Aquí, si puede aparecer una función, puesto que GROUP BY devuelve un único valor por grupo. Para cada valor de
P# distinto en la tabla trabajos, aparecerá su suma total.
Ø
Obtener para cada conductor en el proyecto 'P1', su código y el tiempo máximo trabajado.
SELECT c#, MAX (tiempo)
FROM trabajos
WHERE p# = 'P1'
GROUP BY c#;
Resultado:
c# MAX(tiempo)
C2
100
3.2.7. CLAÚSULA HAVING
HAVING <condicion_de_grupo>
Siempre va acompañada de la cláusula GROUP BY. Especifica una condición de grupo, seleccionándose sólo aquellos
grupos que cumplan la condición especificada. Conceptualmente es como el WHERE, salvo que éste actúa a nivel de tuplas.
Ø
Obtener para los conductores que hayan utilizado la misma máquina más de una vez entre el 12/09/94 y el
18/09/94, el código de conductor, el código de máquina y el tiempo total empleado.
SELECT c#, m#, SUM (tiempo)
FROM trabajos
WHERE fecha BETWEEN 12/09/94 AND 18/09/94
GROUP BY c#, m#
HAVING COUNT(*) > 1;
Resultado:
c# m# SUM(tiempo)
C1 M2
C2 M3
240
110
3.2.8. CLAÚSULA ORDER BY
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 14
ORDER BY <lista_de_atributos> [ASC | DESC]
El resultado de la consulta se ordena en base a los atributos que se indiquen en la lista. Los Atributos de ordenación deben
ser atributos o expresiones que aparezcan en la cláusula SELECT. Cada atributo puede llevar un criterio de ordenación,
ascendente (ASC) o descendente (DESC), por defecto ascendente.
Ø
Obtener los partes de trabajo correspondientes al proyecto 'P4' ordenados ascendentemente por conductor
y máquina.
SELECT *
FROM trabajos
WHERE p# = 'P4'
ORDER BY c#, m#;
Resultado:
C# M# P# FECHA TIEMPO
C1
C1
C3
C5
M2
M3
M1
M3
P4
P4
P4
P4
17/09/94
15/09/94
15/09/94
15/09/94
120
180
300
90
3.2.9. ALIAS DE TABLAS Y COLUMNAS
Se utilizan en los siguientes casos:
1. Para hacer el nombre de una columna más significativo cuando se muestra.
2. Abreviar un nombre de una tabla o de una columna que se usa a menudo.
3. Hacer más clara una instrucción complicada de SQL.
4. Distinguir entre dos ocurrencias del mismo nombre de columna o tabla en cualquier instrucción SELECT.
Ø
Obtener los conductores que tengan la categoría más alta.
SELECT X.nombre CONDUCTOR, X.categ CATEGORIA
FROM conductores X, conductores Y
WHERE X.categ > = Y.categ;
4. LENGUAJE DE CONTROL DE DATOS
4.1. SEGURIDAD DE LOS DATOS
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 15
•
Concesión de privilegios
La concesión de privilegios se utiliza para permitir a los usuarios el acceso completo o restringido a las tablas de la base de
datos.
GRANT <accesos>
ON <lista_de_tablas>
TO <lista_de_cesionarios>|PUBLIC
[WITH GRANT OPTION];
donde:
<accesos>: - ALL PRIVILEGES
- SELECT
- UPDATE
- INSERT
- DELETE
PUBLIC: se conceden los privilegios especificados a todos los usuarios del sistema.
WITH GRANT OPTION: se concede el privilegio de poder otorgar privilegios a otros usuarios.
•
Revocación de privilegios
Se utiliza para anular privilegios ya concedidos a los usuarios.
REVOKE <accesos>
FROM <nombre_usuario> TO <lista_de_tablas>
4.2. INTEGRIDAD DE LOS DATOS
Las instrucciones que permiten mantener la integridad de los datos son:
•
Commit work
Los cambios que se puedan estar realizando sobre la base de datos se hacen fijos únicamente al completar la transacción.
(Transacción: secuencia de operaciones tales que cada operación de la secuencia es necesaria para completar un resultado
unitario. Todas las operaciones deben completarse para que la base de datos quede consistente)
En la base de datos de ejemplo, si eliminamos un proyecto será necesario eliminar las filas de la tabla TRABAJOS que
pertenezcan al proyecto eliminado. Para mantener la integridad de la base de datos o se ejecutan las dos operaciones de borrado
o no se debe ejecutar ninguna.
•
Rollback work
Elimina todos los cambios que se hayan podido producir en la base de datos desde la ejecución de la última instrucción
COMMIT. Si se produce un error de programa o un fallo hardware el sistema realiza un ROLLBACK automáticamente.
5. SQL INMERSO
Como se indicó en la introducción, las sentencias SQL pueden incluirse en un programa de aplicación escrito en un lenguaje
de programación. En este contexto, llamaremos lenguaje anfitrión al lenguaje de programación utilizado, y lenguaje huésped al
lenguaje SQL.
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 16
Para que puedan incluirse sentencias SQL en un programa, es necesario que el SGBDR disponga de un precompilador de
SQL para el lenguaje de programación a utilizar. La función del precompilador es traducir las sentencias SQL que aparezcan en
el programa fuente en llamadas a rutinas del SGBDR.
Una vez precompilado el programa, el fichero resultante se compila con un compilador del lenguaje de programación
utilizado. Como resultado final, se obtiene un programa ejecutable, que interactúa con el SGBDR.
Se llama SQL inmerso, al conjunto de instrucciones SQL que permiten su utilización en programas escritos en lenguajes de
programación.
•
Instrucciones
Todas las instrucciones de SQL inmerso van precedidas de las palabras clave EXEC SQL. Dependiendo del lenguaje de
programación acabarán en punto y coma o en otro indicador.
•
Variables principales
Las variables principales del programa, pueden utilizarse para almacenar el resultado de una consulta que devuelva una sola
fila o bien pueden utilizarse en la propia instrucción SQL.
EXEC SQL SELECT nombre
INTO :nom_cond
FROM conductores
WHERE p# = :variable_principal;
Las variables que se usen en las instrucciones EXEC SQL, deben aparecer en una sección de declaración en el programa
principal. Esta sección comenzará con EXEC SQL BEGIN DECLARE y finalizará con EXEC SQL END DECLARE.
•
Cursores
El resultado de una consulta SQL que devuelva más de una fila no se puede almacenar en variables principales. Para estos
casos se utilizarán los cursores, que son ficheros virtuales de registros, en los que se almacenan el resultado de una consulta (cada
fila un registro). Por tanto un cursor debe asociarse con una consulta, y se declaran de la siguiente forma:
EXEC SQL DECLARE <nombre_cursor> CURSOR FOR <consulta_SQL>;
Para poder utilizar el fichero virtual que representa el cursor es necesario abrirlo primero:
EXEC SQL OPEN <nombre_cursor>;
En el programa que se utilice será necesario la lectura de los registros. La forma de leer un registro del cursor es:
EXEC SQL FETCH <nombre_cursor> INTO <variables_principales>;
Cuando ya no se necesite el cursor, es conveniente cerrarlo:
EXEC SQL CLOSE <nombre_cursor>;
6. EJEMPLOS
BASE DE DATOS DE EJEMPLO
Un empresario que se dedica a la construcción, dispone de una base de datos para gestionar la contratación de maquinarias
(camiones, excavadoras,...) en sus proyectos. En una fecha determinada la base de datos contiene la siguiente información:
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 17
•
•
•
•
TABLA PROYECTOS
P#
DESCRIP
LOCALIDAD
P1
P2
P3
P4
REFORMA VIVIENDA
CONSTRUCCION CHALET
REFORMA VIVIENDA
CONSTRUCCION PISCINA
ARGANDA
RIVAS
ARGANDA
LOECHES
CLIENTE
FELIPE GARCIA
PEDRO MARTINEZ
ROSA ALVAREZ
FERMIN BLANCO
TABLA MAQUINAS
M#
NOMBRE
PRECIO_HORA
M1
M2
M3
EXCAVADORA
HORMIGONERA
VOLQUETE
15000
20000
10000
TABLA CONDUCTORES
C#
NOMBRE
LOCALIDAD
C1
C2
C3
C4
C5
JOSE SANCHEZ
MANUEL DIAZ
JUAN PEREZ
LUIS ORTIZ
JAVIER MARTIN
ARGANDA
ARGANDA
RIVAS
ARGANDA
LOECHES
CATEG
18
15
20
18
12
TABLA TRABAJOS
C#
M#
P#
FECHA
C2
C3
C5
C4
C1
C2
C3
C2
C1
C5
C1
C2
M3
M1
M3
M3
M2
M3
M1
M3
M3
M3
M2
M3
P1
P2
P2
P2
P2
P3
P4
P2
P4
P4
P4
P1
10/09/94
10/09/94
10/09/94
10/09/94
12/09/94
13/09/94
15/09/94
15/09/09
15/09/94
15/09/94
17/09/94
18/09/94
TIEMPO
100
200
150
90
120
30
300
45
180
90
120
35
6.1. CREACIÓN DE LA BASE DE DATOS.
•
Creación de la tabla de proyectos:
CREATE TABLE PROYECTOS
( P#
CHAR(2) UNIQUE NOT NULL,
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 18
DESCRIP CHAR(20) NOT NULL,
LOCALIDAD CHAR(15),
CLIENTE CHAR(20) NOT NULL);
El atributo P# se define como UNIQUE NOT NULL, puesto que es la clave de la tabla, y por tanto no debe tener valores
duplicados (por la definición de clave) ni valores nulos (integridad de la entidad). Los atributos DESCRIP y CLIENTE se
definen como NOT NULL, por considerar que es información que no debe faltar al insertar una fila (del mismo modo se
podría considerar LOCALIDAD).
Al ejecutar esta sentencia se creará la definición de la tabla PROYECTOS (la tabla estará vacía, sin filas), almacenándose
dicha definición en el diccionario de datos (tablas propias del sistema que contienen el esquema de la base de datos).
•
Creación de la tabla partes de trabajo:
CREATE TABLE TRABAJOS
( C# CHAR(2) NOT NULL,
M# CHAR(2) NOT NULL,
P# CHAR(2) NOT NULL,
FECHA DATE NOT NULL,
TIEMPO SMALLINT );
Los atributos que forman parte de la clave de esta tabla se han definido como NOT NULL (integridad de la entidad), pero
en cualquier caso los atributos simples que son clave en otra tabla se deben definir como NOT NULL para mantener la
integridad referencial. En este caso, puesto que la clave está formada por más de un atributo no podemos definir los atributos
que la forman como UNIQUE, ya que lo que no debe repetirse es el valor de la clave, y no el valor de los atributos que la
forman. Para establecer la unicidad de la clave, crearemos un índice.
CREATE UNIQUE INDEX clave_trabajo
ON TRABAJOS (C#, M#, P#, FECHA);
De esta forma aseguramos la unicidad de la clave, al definir un índice con los atributos que la componen como único.
Podríamos crear también índices para cada una de las demás tablas, sobre las claves de éstas, ya que estos atributos
participarán en las uniones naturales cuando las consultas involucren más de una tabla. De esta forma, se tardará menos
tiempo en ejecutar estas consultas. También se podrían crear índices para aquellos atributos que se consulten frecuentemente
(por ejemplo nombre de conductor).
Los índices deben crearse para asegurar la unicidad de una clave compuesta por más de un atributo, o para optimizar el
acceso en las consultas. La creación de los índices debe estudiarse detenidamente, ya que al actualizar una tabla (insertar
y borrar una fila, o modificar valores de los atributos que forman la clave de un índice) el sistema debe actualizar también
los ficheros índices. Esta actualización consume tiempo, y si el número de índices es elevado, puede no ser rentable la
optimización en consultas por el retraso en tiempo que sufren las actualizaciones.
•
Creación de una vista de usuario.
Imaginemos ahora, que una consulta frecuente a la base de datos, es obtener los partes de trabajo, pero queremos que en
el resultado no salgan códigos sino sus nombres asociados. Podríamos crear una vista a tal fin:
CREATE VIEW partes_trabajo (proyecto, conductor, maquina, fecha, minutos)
AS (SELECT descrip, conductores.nombre, maquinas.nombre, fecha, tiempo
FROM proyectos, conductores, maquinas, partes
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 19
WHERE trabajos.p# = proyectos.p# AND
trabajos.c# = conductores.c# AND
trabajos.m# = maquinas.m#);
Al ejecutar esta sentencia el sistema creará la definición de la vista partes_trabajo. Esta vista nunca contendrá filas (es una
tabla virtual), sus filas corresponderán al resultado de la consulta sobre la que está definida. Por ejemplo, la consulta:
SELECT conductor, maquina, fecha, minutos
FROM partes_trabajo
WHERE proyecto = 'CONSTRUCCION CHALET';
dará como resultado:
CONDUCTOR
MAQUINA
FECHA
JUAN PEREZ
JAVIER MARTIN
LUIS ORTIZ
JOSE SANCHEZ
MANUEL DIAZ
EXCAVADORA
10/09/94
VOLQUETE
10/09/94
VOLQUETE
10/09/94
HORMIGONERA 12/09/94
VOLQUETE
15/09/94
MINUTOS
200
150
90
120
45
6.2. ACTUALIZACIÓN DE LA BASE DE DATOS
•
Inserción de filas
Ø
Insertar un nuevo proyecto
INSERT INTO proyectos
VALUES ('P5', 'ALICATAR SUELO', 'ARGANDA','MARIA MARTIN');
•
Actualización de filas
Ø
Subir el precio_hora de todas las máquinas en un 10%
UPDATE maquinas
SET precio_hora = precio_hora * 1.1;
Ø
Incrementar la categoría de los conductores de Arganda con la tercera
parte de la categoría más baja.
UPDATE conductores
SET categ = categ + (SELECT categ/6
FROM conductores
WHERE categ = (SELECT MIN(categ)
FROM conductores) )
WHERE localidad = 'ARGANDA';
Esta solución no es válida en Informix_sql, ya que no permite que se realice una consulta sobre la tabla que se está
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 20
modificando en la asignación del nuevo valor para el atributo. La actualización puede realizarse con éxito utilizando una
tabla temporal como se muestra a continuación:
SELECT (categ/6) tercio
FROM conductores
WHERE categ IN (SELECT MIN (categ)
FROM conductores)
INTO TEMP minima;
UPDATE conductores
SET categ = categ + (SELECT tercio
FROM minima)
WHERE localidad = 'ARGANDA';
DROP TABLE minima;
De esta forma, utilizamos una tabla temporal en la que se almacena la tercera parte de la categoría más baja en el
atributo tercio, y posteriormente se actualiza el valor de categoría consultando dicha tabla temporal. Por último
eliminamos la tabla temporal, aunque no sería del todo necesario, porque el sistema elimina las tablas temporales al
abandonar el entorno sql.
•
Borrado de filas
Ø
Eliminar de la base de datos al conductor Javier Martín.
DELETE
FROM conductores
WHERE nombre = 'JAVIER MARTIN';
Con esta sentencia eliminamos al conductor, pero la base de datos puede quedar inconsistente, ya que en la tabla
TRABAJOS puede figurar el código de éste (no debe consentirse nunca la aparición de inconsistencias en la base de
datos, ya que dan lugar a resultados incorrectos).
Para evitar que esta eliminación provoque una inconsistencia, habrá que eliminar de la base de datos cualquier referencia
al conductor eliminado. En nuestro caso, C# está definido como NOT NULL en la tabla TRABAJOS, por tanto habrá
que eliminar todas las filas de esta tabla en las que aparezca el conductor eliminado para dejar la base de datos
consistente. Si admitiera valores nulos en lugar de eliminar la fila entera podríamos modificar el valor del código de
conductor con NULL.
DELETE
FROM trabajos
WHERE c# NOT IN (SELECT c# FROM conductores);
También podíamos haber realizado la siguiente secuencia:
DELETE
FROM trabajos
WHERE c# IN (SELECT c#
FROM conductores
WHERE nombre = 'JAVIER MARTIN');
DELETE
FROM conductores
WHERE nombre = 'JAVIER MARTIN');
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 21
Las dos operaciones de eliminación de datos (eliminación en trabajos y en conductores), deben ejecutarse como una
transacción única, de tal forma que se ejecuten las dos operaciones o no se ejecute ninguna.
6.3. RECUPERACIONES O CONSULTAS A LA BASE DE DATOS.
Ø
Obtener el nombre de los trabajadores que han participado en proyectos realizados en la localidad de Arganda.
SELECT nombre
FROM conductores
WHERE c# IN (SELECT c#
FROM trabajos
WHERE p# IN (SELECT p#
FROM proyectos
WHERE localidad = 'ARGANDA'));
Resultado:
NOMBRE
MANUEL DIAZ
ó:
SELECT nombre
FROM conductores, trabajos, proyectos
WHERE proyecto.localidad = 'ARGANDA' AND
proyectos.p# = trabajos.p# AND
trabajos.c# = conductores.c#;
Resultado:
NOMBRE
MANUEL DIAZ
MANUEL DIAZ
MANUEL DIAZ
En esta segunda solución es necesario indicar la tabla del atributo LOCALIDAD, ya que podría haber ambigüedad con el
atributo LOCALIDAD de la tabla PROYECTOS. Por otra parte, si no queremos que aparezcan tuplas duplicadas en el
resultado podemos incluir la opción UNIQUE:
SELECT UNIQUE nombre
Ø
Obtener el importe total de los trabajos realizados al cliente Felipe García, más el 20% de beneficio de la
empresa.
SELECT SUM(tiempo*precio_hora/60)*1.20 'IMPORTE_TOTAL'
FROM trabajos, maquinas, proyectos
WHERE cliente = 'FELIPE GARCIA' AND
proyectos.p# = trabajos.p# AND
trabajos.m# = maquinas.m#;
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 22
Resultado:
IMPORTE_TOTAL
1620000
En este ejemplo, se calcula la suma de las cantidades resultantes de multiplicar el tiempo (expresado en minutos) empleado
por cada máquina en los diferentes proyectos que se hayan realizado al cliente Felipe García, por el coste de la máquina por
minuto (coste de una hora dividido entre 60 minutos). El resultado de dicha suma se multiplica por 1.20 para obtener, el
coste total más el 20%. Se ha especificado un literal ('IMPORTE_TOTAL') para que este sea la cabecera de la tabla
resultado.
Ø
Obtener nombre de los conductores que no tengan la categoría más alta.
SELECT nombre
FROM conductores
WHERE categ NOT IN (SELECT MAX(categ)
FROM conductores);
Resultado:
NOMBRE
MANUEL DIAZ
JAVIER MARTIN
ó:
SELECT x.nombre
FROM conductores x, conductores y
WHERE x.categ < y.categ;
Resultado:
X.NOMBRE
MANUEL DIAZ
MANUEL DIAZ
MANUEL DIAZ
JAVIER MARTIN
JAVIER MARTIN
JAVIER MARTIN
JAVIER MARTIN
En esta segunda solución se utilizan mediante el empleo de alias de tabla, dos copias de la misma tabla (conductores), que
a efectos de la consulta son tratadas como dos tablas diferentes. Si no queremos que aparezcan filas duplicadas en la tabla
resultado:
SELECT UNIQUE x.nombre
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 23
Ø
Obtener el tiempo total empleado en cada proyecto.
SELECT p#, SUM(tiempo)
FROM trabajos
GROUP BY p#;
Resultado:
P# SUM(tiempo)
P1
P2
P3
P4
135
605
30
690
En esta consulta, al agrupar por el atributo p#, se obtiene por cada valor diferente de p# en la tabla TRABAJOS el valor
de la función especificada. Es decir, por todas las filas que tienen el mismo valor de p# (grupo) se obtiene la suma
correspondiente al valor del atributo TIEMPO.
Ø
Conductores que han participado en todos los proyectos de Arganda.
SELECT nombre
FROM conductores, trabajos, proyectos
WHERE proyecto.localidad = 'ARGANDA' AND
conductores.c# = trabajos.c# AND
trabajos.p# = proyectos.p#
GROUP BY nombre
HAVING COUNT (DISTINCT p#) = (SELECT COUNT (p#)
FROM proyectos
WHERE localidad = 'ARGANDA');
Resultado:
NOMBRE
MANUEL DIAZ
En la cláusula WHERE especificamos las condiciones de fila para obtener los datos relativos a los conductores que han
participado en proyectos realizados en Arganda. Después se agrupa por nombre y especificamos que por cada grupo
(nombre de conductor) el número de proyectos distintos en los que ha participado debe ser igual al número de proyectos
realizados en Arganda.
Ø
Obtener el código del proyecto en el que más tiempo se ha empleado.
SELECT p#
FROM trabajos
GROUP BY p#
HAVING SUM(tiempo) IN (SELECT MAX(SUM(tiempo))
FROM trabajos
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 24
GROUP BY p#);
Esta solución que es válida en SQL estándar, no lo es en la versión de Informix_sql que utilizaremos en las prácticas, ya que
no permite anidar funciones. Para solucionar este problema, podemos crear una tabla temporal para obtener los valores
correspondientes a la primera función. Veamos una posible solución:
SELECT SUM(tiempo) suma
FROM trabajos
GROUP BY p#
INTO TEMP sumas;
SELECT p#
FROM trabajos
GROUP BY p#
HAVING SUM(tiempo) IN (SELECT MAX(suma)
FROM sumas);
Resultado:
P#
P4
La primera consulta crea la tabla temporal SUMAS, en la que se almacena en el atributo SUMA, la suma de los tiempos
empleados para cada uno de los proyectos. En la segunda consulta para cada proyecto, se comprueba si la suma del tiempo
empleado coincide con el proyecto con mayor tiempo empleado. Una vez realizada la consulta es conveniente eliminar la
tabla temporal, ya que si antes de abandonar la sesión se intenta ejecutar de nuevo esta consulta aparecerá un error al
intentar crear una tabla temporal ya existente. En cualquier caso, al abandonar la sesión desaparecen todas las tablas
temporales que se hayan podido crear durante ésta.
Pedro Pablo Alarcón Cavero
SQL_Estándar. Pág. 25
Descargar