0% encontró este documento útil (0 votos)
158 vistas

Introducción Al Lenguaje Estructurado de Consultas (SQL)

El documento introduce los conceptos básicos de SQL, incluyendo cómo seleccionar datos de una tabla usando la sentencia SELECT, agregar condiciones a la selección usando la cláusula WHERE y operadores como =, <, >, BETWEEN e IN, y unir tablas. Explica cómo seleccionar columnas específicas, filtrar filas basadas en criterios, usar operadores lógicos como AND y OR, y realizar búsquedas parciales con LIKE.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
158 vistas

Introducción Al Lenguaje Estructurado de Consultas (SQL)

El documento introduce los conceptos básicos de SQL, incluyendo cómo seleccionar datos de una tabla usando la sentencia SELECT, agregar condiciones a la selección usando la cláusula WHERE y operadores como =, <, >, BETWEEN e IN, y unir tablas. Explica cómo seleccionar columnas específicas, filtrar filas basadas en criterios, usar operadores lógicos como AND y OR, y realizar búsquedas parciales con LIKE.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 57

Introducción al Lenguaje Estructurado de Consultas (SQL) 

CAPÍTULO 1. Introducción

 
 
Bases de la sentencia SELECT

En una BD relacional, los datos son almacenados en tablas. Un ejemplo de tabla puede contener el DNI, el
nombre y la Dirección:
 
 
Tabla_direcciones_empleados

DNI Apellidos Nombre Dirección Ciudad

23987739 García Antonio C/ Mayor 2 Valencia

45623890 López Juan Pl. Ayuntamiento Alicante

Ahora, vamos a ver que habría que hacer para ver las direcciones de todos los empleados. Utiliza la sentencia
SELECT de la siguiente manera:

SELECT Nombre, Apellidos, Dirección, Ciudad, Provincia


FROM Tabla_direcciones_empleados;

Los siguiente es el resultado de tu consulta de la BD:

 Nombre     Apellidos     Dirección             Ciudad     Provincia


 ------------------------------------------------------
 Antonio     García           C/ Mayor2            Valencia Valencia
 Juan           López            Pl. Ayuntamiento  Alicante   Alicante
 
La explicación de lo que acabas de hacer es la siguiente, has preguntado por todos los datos de la
Tabla_direcciones_empleados, y específicamente, has preguntado por la columnas llamadas Nombre,
Apellidos, Dirección, Ciudad y Provincia. Date cuenta que los nombre de las columnas y los nombres de las
tablas no tienen espacios...éstos deben ser escritos con una palabra; y que la sentencia acaba con un punto y
coma (;). La forma general para una sentencia SELECT, recuperando  las filas de una tabla es:

SELECT NombreColumna, NombreColumna, ...


FROM NombreTabla;

Para coger todas las columnas de una tabla sin escribir todos los nombres de columna, usa:

SELECT * FROM NombreTabla;

Cada administrador de BD's (DBMS, "Data Management System") y tipo de software de BD's tienen
diferentes métodos para identificarse en la base de datos e introducir comandos SQL.

Selección Condicional
 
Para un mayor estudio de la sentencia SELECT, echa un vistazo a una nueva tabla de ejemplo:
 
 
 
Tabla_estadistica_empleados

Cod_empleado Salario Beneficios Cargo

101 75000 15000 Encargado

105 65000 15000 Encargado

152 60000 15000 Encargado

215 60000 12500 Encargado

244 50000 12000 Técnico

300 45000 10000 Técnico

335 40000 10000 Técnico

400 32000 7500 Aprendiz

441 28000 7500 Aprendiz

Operadores Relacionales
 
Hay seis operadores relacionales en SQL, y después de introducirlos, veremos como usarlos:
 
= Igual
< ó != No igual (ver manual para más información)
< Menor que
  Mayor que
<= Menor o igual a
= Mayor o igual que
La cláusula WHEREes usada para especificar que sólo ciertas filas de la tabla sean mostradas, basándose en
el criterio descrito en esta cláusula WHERE. Es más fácil de entender viendo un par de ejemplos:
Si quieres ver el Cod_empleado de aquellos que tengan un salario por encima de 50.000, usa la siguiente
expresión:
 
SELECT Cod_empleado
FROM Tabla_estadistica_empleados
WHERE Salario = 50000;

Observa que el signo = (mayor o igual que) ha sido usado, ya que queremos ver listados juntos aquellos que
ganen más de 50.000 o igual a 50.000 . Esto muestra:

Cod_empleado
---------------
010
105
152
215
244

La descripción WHERE Salario = 50.000, es conocida como condición. Lo mismo puede ser utilizado para la
columnas de tipo texto:

SELECT Cod_empleado
FROM Tabla_estadistica_empleados
WHERE Cargo = 'Encargado';

Esto muestra la código de todos los encargados. Generalmente, con las columnas de texto, usa igual o no igual
a, y comprueba que el texto que aparece en la condición está dentro de comillas simples.

Más Condiciones Complejas: Condiciones Compuestas


 
El operador AND junta dos o más condiciones, y muestra sólo las filas que satisfacen TODAS las condiciones
listadas. Por ejemplo:

SELECT Cod_empleado
FROM Tabla_estadistica_empleados
WHERE Salario 40000 AND Cargo = ‘Técnico’

El operador OR junta dos o más condiciones, y devuelve una fila si ALGUNA de las condiciones listadas en
verdadera. Para ver todos aquellos que ganan menos de 40.000 o tienen menos de 10.000 en beneficios
listados juntos, usa la siguiente consulta:

SELECT ID_EMPLEADO
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE SALARIO < 40000 OR BENEFICIOS < 10000;

AND & OR pueden ser combinadas, por ejemplo:

SELECT ID_EMPLEADO
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE CARGO = 'Encargado' AND SALARIO 60000 OR BENEFICIOS 12000;

Primero, SQL encuentra las filas donde el salario es mayor de 60.000 y la columna del cargo es igual a
Encargado, una vez tomada esta nueva lista de filas, SQL buscará si hay otras filas que satisfagan la condición
AND previa o la condición  que la columna de los Beneficios sea mayor de 12.000. Consecuentemente, SQL
solo muestra esta segunda nueva lista de filas, recordando que nadie con beneficios sobre 12.000 será excluido
ya que el operador OR incluye una fila si el resultado de alguna de las partes es VERDADERO.
Date cuenta que la operación AND se ha hecho primero.

Para generalizar este proceso, SQL realiza las operaciones AND para determinar las filas donde las
operaciones AND se mantienen VERDADERO (recordar: todas las condiciones son verdaderas), entonces
estos resultados son usados para comparar con las condiciones OR, y solo muestra aquellas filas donde las
condiciones unidas por el operador OR se mantienen ciertas para alguna de las partes de la condición..

Para realizar OR antes de AND, p.e., si quisieras ver una lista de empleados ganando un gran salario (50.000)
o con un gran beneficio (10.000), y sólo quieres que lo mire para los empleados con el cargo de Encargado,
usa paréntesis:
SELECT ID_EMPLEADO
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE CARGO = 'Encargado' AND (SALARIO 50000 OR BENEFICIO 10000);

IN & BETWEEN
 
Un método fácil de usar condiciones compuestas es usando IN o BETWEEN. Por ejemplo si tu quieres listar
todos los encargados y Técnico:

SELECT ID_EMPLEADO
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE CARGO IN ('Encargado', 'Técnico');

 O para listar aquellos que ganen más o 30.000, pero menos o igual que 50.000, usa:

SELECT ID_EMPLEADO
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE SALARIO BETWEEN 30000 AND 50000;

 Para listar todos los que no están en este rango, intenta:

SELECT ID_EMPLEADO
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE SALARIO NOT BETWEEN 30000 AND 50000;
 
De forma similar, NOT IN lista todas las filas excluyendo aquellas de la lista IN.

Usando LIKE

 Observa la Tabla_estadistica_empleados, y di que quieres ver todas las personas en las cuales su apellido
comience por "l":, intenta:

SELECT ID_EMPLEADO
WHERE APELLIDOS LIKE 'L%';
FROM TABLA_ESTADISTICA_EMPLEADOS

 El tanto por ciento (%) es usado para representar un posible carácter (sirve como comodín), ya sea número,
letra o puntuación, o para seleccionar todos los caracteres que puedan aparecer después de "L". Para encontrar
las personas con el apellidos terminado en "L", usa ‘%L’, o si quieres la ‘L’ en medio de la palabra ‘%L%’. El
‘%’ puede ser usado en lugar de cualquier carácter en la misma posición relativa a los caracteres dados. NOT
LIKE muestra filas que no cumplen la descripción dada. Otras posibilidades de uso de LIKE, o cualquiera de
las condiciones anteriores son posibles, aunque depende de qué DBMS estés usando; lo más usual es consultar
el manual, o tu administrador de sistema sobre la posibilidades del sistema, o sólo para estar seguro de que lo
que estás intentando hacer es posible y correcto. Éste tipo de peculiaridades serán discutidas más adelante.
Esta sección sólo pretende dar una idea de las posibilidades de consultas que pueden ser escritas en SQL.

CAPÍTULO 2.  Uniones

 
Uniones
 
En esta sección, sólo estudiaremos las uniones de unión, y intersección, que en general son las más usadas.

Un buen diseño de una BD sugiere que cada lista de tabla de datos sea considerada como una simple entidad,
y que la información detallada puede ser obtenida, en una BD relacional, usando tablas adicionales y  uniones.

Primero considera los siguientes ejemplos de tablas:


 
 
Propietarios_Antigüedades

ID_Propietario ApellidoPropietario NombrePropietario

01 Jones Bill

02 Smith Bob

15 Lawson Patricia

21 Akins Jane

50 Fowler Sam

 
 
Pedidos

ID_Propietario ProductoPedido

02 Table

02 Armario

21 Silla

15 Espejo

 
 
Antigüedades

ID_vendedor ID_comprador Producto

01 50 Cama

02 15 Table

15 02 Silla

21 50 Espejo

50 01 Armario
01 21 Cabinet

02 21 Cofee Table

15 50 Cahair

01 15 Jewelry Box

02 21 Pottery

21 02 Librería

50 01 Plant Stand

Claves

Primero, vamos a estudiar el concepto de claves. Una clave primaria es una columna o conjunto de columnas
que identifican unívocamente el resto de datos en cualquiera fila. Por ejemplo, en la tabla
Propietarios_Antigüedades, la columna ID_Propietario identifica unívocamente esa fila. Esto significa dos
cosas: dos filas no pueden tener el mismo ID_Propietario y, aunque dos propietarios tuvieran el mismo
nombre y apellidos, la columna ID_Propietario verifica que no serán confundidos, porque la columna
ID_Propietario podrá ser usada por el Administrador de la Base de Datos (DBMS) para diferenciarlos, aunque
los nombres sean los mismos.

 Una clave ajena es una columna en una tabla que es clave primaria en otra tabla, lo que significa que cada
dato en una columna con una clave ajena debe de corresponder con datos, en otra tabla, cuya columna es
clave primaria. En el lenguaje DBMS esta correspondencia es conocida como integridad referencial. Por
ejemplo, en la tabla Antigüedades, tanto el ID_comprador como el ID_vendedor son claves ajenas de la clave
primaria de la tabla Propietarios_Antigüedades (ID_Propietario; por supuesto, se tiene que tener un
propietario antiguo antes de poder comprar o vender cualquier producto), por lo tanto, en ambas tablas, las
columnas ID son usadas para identificar los propietarios o compradores y vendedores, y por lo tanto
ID_Propietario es la clave primaria de la tabla Propietarios_Antigüedades. En otras palabras, todos estos datos
"ID" son usados para referirse a los propietarios, compradores, o vendedores de antigüedades, sin necesidad de
usar sus nombres reales.

Creando una Unión

El propósito de estas claves es el poder referirse a datos de diferentes tablas, sin tener que repetir los datos en
cada una de ellas, este es el poder de las bases de datos relacionales. Por ejemplo, se pueden encontrar los
nombres de los que han comprado una silla sin tener que listar el nombre completo de el comprador en la
tabla Antigüedades...puedes conseguir el nombre relacionando aquellos que compraron una silla con los
nombres en la tabla de Propietarios_Antigüedades usando el ID_Propietario, el cual relaciona los datos en las
dos tablas. Para encontrar los nombres de aquellos que compraron una silla, usa la siguiente consulta:

SELECT APELLIDOPROPIETARIO, NOMBREPROPIETARIO


FROM PROPIETARIOS_ANTIGÜEDADES, ANTIGÜEDADES
WHERE ID_COMPRADOR = ID_PROPIETARIO AND PRODUCTO = 'Silla';

Date cuenta de lo siguiente sobre la consulta... las tablas involucradas en la relación son listadas en la cláusula
FROM de la sentencia. En la cláusula WHERE, primero observa que el PRODUCTO=’Silla’ restringe el
listado a aquellos que han comprado una silla. Segundo, observa como las columnas ID son relacionadas de
una tabla a otra por el uso de la cláusula ID_COMPRADOR=ID_PROPIETARIO. Sólo cuando los ID
coinciden y el objeto comprado es una silla (por el AND), los nombres de la tabla Propietarios_Antigüedades
serán listados. Debido a que la condición de unión usada es el signo igual, esta unión se denomina
intersección. El resultado de esta consulta son dos nombres: Smith, Bob & Fowler, Sam.

Para evitar ambigüedades se puede poner el nombre de la tabla antes del de la columna, algo como:
SELECT PROPIETARIOS_ANTIGÜEDADES.APELLIDOPROPIETARIO,
PROPIETARIOS_ANTIGÜEDADES.NOMBREPROPIETARIO
FROM PROPIETARIOS_ANTIGÜEDADES, ANTIGÜEDADES
WHERE ANTIGÜEDADES.ID_COMPRADOR = PROPIETARIOS_ANTIGÜEDADES.ID_PROPIETARIO
AND ANTIGÜEDADES.PRODUCTO = 'Silla';

 Sin embargo, como los nombres de las columnas en cada tabla son diferentes, esto no es necesario.

DISTINCT y Eliminando Duplicados

Consideremos que quieres ver los ID y los nombres de toda aquellas persona que haya vendido una
antigüedad. Obviamente,  quieres una lista donde cada vendedor sea listado una vez, y no quieres saber
cuántos artículos a vendido una persona, solamente el nombre de las personas que han vendido alguna
antigüedad (para contar, ver la sección próxima Funciones Agregadas). Esto significa que necesitaras decir en
SQL que quieres eliminar las filas de vendedores duplicadas, y sólo listar cada persona una vez. Para hacer
esto, uso la palabra clave DISTINCT.

Primero, necesitaremos una intersección para la tabla de Propietarios_Antigüedades para conseguir los datos
detallados de las personas, apellidos y nombre.

Sin embargo, recuerda que la columna ID_vendedor de la tabla Antigüedades es una clave ajena para la tabla
Propietarios_Antigüedades, y por tanto, un vendedor podría ser listado más de una vez, por cada producto de
la tabla Antigüedades, listando el ID y sus datos, como queremos eliminar múltiples coincidencias del
ID_vendedor en nuestra lista, usaremos DISTINCT en la columna donde las repeticiones pueden ocurrir.

Para complicarlo un poco más, además queremos la lista ordenada alfabéticamente por el Apellido, después
por el Nombre, y por último por su ID_Propietario. Para ello, usaremos la clausula ORDER BY.

SELECT DISTINCT ID_VENDEDOR, APELLIDOPROPIETARIO, NOMBREPROPIETARIO


FROM ANTIGÜEDADES, PROPIETARIOS_ANTIGÜEDADES
WHERE ID_VENDEDOR = ID_PROPIETARIO
ORDER BY APELLIDOPROPIETARIO, NOMBREPROPIETARIO, ID_PROPIETARIO;

En este ejemplo, obtendremos un listado de todos los propietarios, en orden alfabético por el Apellido. Para
futuras referencias (y si alguien pregunta), este tipo de uniones son consideradas en la categoría de uniones
interiores.

Alias & In/Subconsultas


En esta sección, hablaremos sobre los Alias, In y el uso de las subconsultas, y como éstas pueden ser usadas
en un ejemplo con tres tablas. Primero, observa esta consulta que imprime el apellido de aquellos propietarios
que han formulado un pedido y en qué consiste éste, solamente listando aquellos cuyos pedidos pueden ser
atendidos (esto es, hay un vendedor que posee el producto pedido)

SELECT OWN.APELLIDOPROPIETARIO Apellido, ORD.PRODUCTOPEDIDO Producto Pedido

FROM PEDIDOS ORD, PROPIETARIOS_ANTIGÜEDADES OWN


WHERE ORD.ID_PROPIETARIO = OWN.ID_PROPIETARIO
AND ORD.PRODUCTOPEDIDO IN
    (SELECT PRODUCTO
    FROM ANTIGÜEDADES);

Esto devuelve:
Apellidos Producto Pedido
--------------------------------
Smith         Table
Smith         Armario
Akins         Silla
Lawson     Espejo

 Hay algunas cosas a tener en cuenta sobre esta consulta:

1. Primero, el "Apellido" y el "Producto Pedido" en las líneas Select devuelve los títulos en la salida.
2. El OWN & ORD son alias; éstos son dos nuevos nombres para las dos tablas listadas en la cláusula
FROM que son usado como prefíjos para toda las notaciones con punto de los nombres de las
columnas en la consulta (ver arriba). Esto elimina ambigüedades, especialmente en la cláusula de
intersección WHERE donde ambas tablas tienen la columna ID_Propietario, y la notación con punto
dice al SQL que estamos refiriéndonos de dos diferentes ID_Propietario de dos tablas diferentes.

3. Observa que la tabla de Pedidos está utilizada primero en la cláusula FROM; esto asegura que el
listado hecho basándose en esta tabla, y la tabla AntiquesOwners, es solamente usado para la
información complementaria (apellidos).

4. Más importante, el AND en la cláusula WHERE fuerza en la subconsulta el ser invocada ("=ANY" or
"=SOME", son dos equivalente usos de IN). Qué significa esto, la subconsulta se realiza, devolviendo
todos los productos que pertenecen a alguien de la tabla de Antigüedades, como si no hubiera la
cláusula WHERE. Así pues, para que una fila de la tabla de Pedidos sea listada, el ProductoPedido
debe de ser devuelto en la lista de productos con propietario de la tabla de Antigüedades, ésta lista un
producto sólo si el pedido puede ser cumplido por otro propietario. Puedes pensar que este es el
camino: la subconsulta devuelve un conjunto de productos los cuales son comparados con los de la
tabla Pedidos; la condición In es verdadera sólo si el producto deseado está en el conjunto devuelto
de la tabla Antigüedades. Además, date cuenta que este caso, en el que hay una antigüedad
disponible para cada demanda, obviamente no será siempre el caso. Además, observa que cuando IN,
"=ANY", o "=SOME" es usada, estas palabras claves se refieren a cualquier posible fila seleccionada,
no a columnas seleccionadas...esto es, no puedes poner múltiples columnas en una.

CAPÍTULO 3. Misceláneo de Sentencias SQL

Funciones Agregadas
 
Vamos a ver cinco importantes funciones agregadas: SUM, AVG, MAX , MIN y COUNT. Son llamadas
funciones agregadas porque resumen el resultado de una consulta.
 
 
devuelve el total de todas las fila, satisfaciendo todas las condiciones de una columna dada,
SUM ()
cuando la columna dada es numérica.
AVG ()  devuelve la media de una columna dada.
MAX () devuelve el mayor valor de una columna dada.
MIN () devuelve el menor valor en una columna dada.
COUNT(*)  devuelve el número de filas que satisfacen las condiciones.

Viendo las tablas del principio del documento, veamos tres ejemplos:
SELECT SUM(SALARIO), AVG(SALARIO)
FROM TABLA_ESTADISTICA_EMPLEADOS;

 Esta consulta muestra el total de todos los salarios de la tabla, y la media salarial de todas las entradas en la
tabla.

SELECT MIN(BENEFICIOS)
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE CARGO = 'Encargado';

Esta consulta devuelve el menor valor de la columan de beneficios, de los empleados que son Managers, la
cual es 12.500.

SELECT COUNT(*)
FROM TABLA_ESTADISTICA_EMPLEADOS
WHERE CARGO = 'Técnico';

Esta consulta nos dice cuantos empleados tienen la categoría de Técnico (3).

Vistas
 
En SQL, tu puedes (comprueba tu DBA) tener acceso a crear vistas por ti mismo. Lo que una vista hace es
permitirte asignar resultados de una consulta a una tabla nueva y personal , que puedes usar en otras consultas,
pudiendo utilizar el nombre dado a la tabla de tu vista en la cláusula FROM. Cuando accedes a una vista, la
consulta que está definida en la sentencia que crea tu lista está relacionada (generalmente), y los resultados de
esta consulta son como cualquier otra tabla en la consulta que escribiste invocando tu vista. Por ejemplo, para
crear una vista:

CREATE VIEW ANTVIEW AS SELECT PRODUCTOPEDIDO FROM PEDIDOS;

Ahora, escribe una consulta usando esta vista como tabla, donde la tabla es una listado de todos los Productos
Pedidos de la tabla Pedidos:

SELECT ID_VENDEDOR
FROM ANTIGÜEDADES, ANTVIEW
WHERE PRODUCTOPEDIDO = PRODUCTO;

Esta consulta muestra todos los ID_vendedor de la tabla de Antigüedades donde el producto, en esta tabla,
aparece en la vista Antview, la cual no es más que todos los Productos Desired de la tabla Pedidos. El listado
es generado yendo uno por uno por los Productos Antigüos hasta donde hay una coincidencia con la vista
Antview. Las vistas pueden ser usadas para restringir el acceso a las bases de datos, así como para simplificar
una consulta compleja.

Creando nuevas tablas

Toda  tabla de una base de datos debe de ser creada alguna vez... veamos como hemos creado la tabla de
Pedidos:

CREATE TABLE PEDIDOS


    (ID_PROPIETARIO INTEGER NOT NULL,
     PRODUCTOPEDIDO CHAR(40) NOT NULL);

 Esta sentencia devuelve el nombre de la tabla e informa a la DBMS sobre cada columna en la tabla. Observa
que esta sentencia usa tipos de datos genéricos, y que los tipos de datos pueden ser diferentes dependiendo del
DBMS que estes usando. Algunos tipos de datos genéricos son:
- Char(x) - Una columna de caracteres, donde x es el número máximo de caracteres permitido en la columna.
- Integer – Una columna de números enteros, positivos o negativos.
- Decimal(x, y) – Una columna de números decimales, donde x es el número máximo de digitos del número
decimal en la columna e y el número máximo de dígitos después del punto decimal. Ejemplo: (4,2): 99.99.
- Date - Una columna fecha tiene un formato especial en cada DBMS.
- Logical – Una columna que sólo puede tomar dos valores: TRUE o FALSE (verdadero o falso).

 Otra nota, NOT NULL significa que la columna debe tener un valor en cada fila. Si NULL es usado, la
columna podría tener un valor vacio en una de sus filas.

 
Modificando Tablas

Vamos a añadir una columna a la tabla Antigüedades para permitir introducir el precio de un producto dado:

ALTER TABLE ANTIGÜEDADES ADD (PRECIO DECIMAL(8,2) NULL);

Los datos para esta nueva columna pueden ser actualizados o insertados como se muestra a continuación.

Añadiendo Datos
 
Para insertar filas en una tabla, haz lo siguiente:

INSERT INTO ANTIGÜEDADES VALUES (21, 01, 'Ottoman', 200.00);

Esto inserta los datos en la tabla, como una nueva fila, columna por columna, en el orden pre-definido.
Veamos como modificar el orden y dejar el Precio en blanco:

INSERT INTO ANTIGÜEDADES (ID_COMPRADOR, ID_VENDEDOR, PRODUCTO)


VALUES (01, 21, 'Ottoman');

Borrando datos

 Vamos a borrar esta nueva fila de al base de datos:

DELETE FROM ANTIGÜEDADES


WHERE PRODUCTO = 'Ottoman';

 Pero si hay otra fila que contiene ‘Ottoman’, esta fila también será borrada. Para diferenciar la fila de otra, lo
que haremos será añadir datos:

DELETE FROM ANTIGÜEDADES


WHERE PRODUCTO = 'Ottoman' AND ID_COMPRADOR = 01 AND ID_VENDEDOR = 21;

Actualizando Datos

Vamos a actualizar el Precio en una fila que todavía no tiene el precio:

UPDATE ANTIGÜEDADES SET PRECIO = 500.00 WHERE PRODUCTO = 'Silla';


Esto pone el precio de todas las sillas a 500.00, como en el caso anterior, añadiendo más condicionantes en la
cláusula WHERE, podemos especificar más aquellas filas que queremos modificar.
 

CAPÍTULO 4. Misceláneo de Tópicos

 
 
Índices
 
Los índices permiten a DBMS acceder a los datos más rápidamente (esto no ocurre en todos los sistemas). El
sistema crea esta estructura de datos interna (el índice) con la cual se es posible seleccionar filas, cuando la
selección se basa en columnas indexadas, esto se hace más rápidamente. Este índice le dice a la DBMS donde
esta cierta fila dando el valor de una columna indexada, como un libro, cuyo índice te dice en que páginas
aparece una cierta palabra. Vamos a crear un índice por el ID_Propietario en la tabla
Propietarios_Antigüedades:

CREATE INDEX OID_IDX ON PROPIETARIOS_ANTIGÜEDADES (ID_PROPIETARIO);

Ahora en los nombres:

CREATE INDEX NAME_IDX ON PROPIETARIOS_ANTIGÜEDADES (APELLIDOPROPIETARIO,


NOMBREPROPIETARIO);

Para borrar un índice, utiliza la sentencia DROP:

DROP INDEX OID_IDX;

Así mismo, también puedes "borrar" una tabla (DROP TABLE nombretabla). En el segundo ejemplo, el
índice se mantine en las dos columnas, agregado junto.

Algunos DBMS no fuerzan la existencia de claves primarias; en otras palabra, la unicidad de una columna no
es forzada automáticamente. Lo que significa que, por ejemplo, si intento insertar otra fila dentro de la tabla
Propietarios_Antigüedades con el ID_Propietario de 02, algunos sistemas lo permitirán hacer, incluso, si esta
columna es la única de la tabla (cada fila se supone que es diferente). Una forma de evitar esto es crear un
único índice en la columna que queramos que sea la clave primaria para forzar al sistema a prohibir los
duplicados.

CREATE UNIQUE INDEX OID_IDX ON PROPIETARIOS_ANTIGÜEDADES (ID_PROPIETARIO);

GROUP BY & HAVING


 
Un uso especial de GROUP BY es asociar una función agregada (especialmente COUNT) con grupos de filas.
Primero, imagina que la tabla Antigüedades tiene la columna Precio, y que cada fila tiene un valor para esta
columna. Queremos ver el precio del producto más caro comprado por cada comprador. Tenemos que decirle
a SQL que agrupe cada tipo de compra, y nos diga la compra que tenga el máximo precio:

SELECT ID_COMPRADOR, MAX(PRECIO)


FROM ANTIGÜEDADES
GROUP BY ID_COMPRADOR;

Ahora, queremos decir que sólo queremos ver la precio máximo de la compra si éste es sobre $1000, así que
usamos la cláusula HAVING:
SELECT ID_COMPRADOR, MAX(PRECIO)
FROM ANTIGÜEDADES
GROUP BY ID_COMPRADOR
HAVING PRECIO 1000;

Más subconsultas
 
Otro uso común de las subconsultas involucra el uso de operadores para permitir a una condición WHERE
incluir la salida de un Select de una subconsulta. Primero, lista los compradores que compraron un producto
caro (el precio del producto es $100 mayor que la media de precio de todos los productos):

SELECT ID_COMPRADOR
FROM ANTIGÜEDADES
WHERE PRECIO
    (SELECT AVG(PRECIO) + 100
     FROM ANTIGÜEDADES);

La subconsulta calcula la media del Precio más $100, y usando esta figura, los ID_Propietario son impresos
por cada producto que cuesta más. Se puede usar DISTINCT ID_PROPIETARIO, para eliminar duplicados.

Lista los apellidos de aquellos de la tabla AntiqueOwner, SÓLO si han comprado un producto:

SELECT APELLIDOPROPIETARIO
FROM PROPIETARIOS_ANTIGÜEDADES
WHERE ID_PROPIETARIO IN
    (SELECT DISTINCT ID_COMPRADOR
     FROM ANTIGÜEDADES);

La subconsulta devuelve la lista de compradores, y el apellido es impreso para un Antique Owner si y sólo si
el ID_Propietario aparece en la lista de la subconsulta (también llamada lista de candidatos). Nota: en algunas
DBMS, el igual puede ser usado de la misma forma que IN, aunque, por previsión, IN es una mejor elección.

Para un ejemplo de actualización, nosotros sabemos que el hombre que compró la librería tiene el Nombre
equivocado en la base de datos, éste debería ser John:

UPDATE PROPIETARIOS_ANTIGÜEDADES
SET NOMBREPROPIETARIO = 'John'
WHERE ID_PROPIETARIO =
    (SELECT ID_COMPRADOR
     FROM ANTIGÜEDADES
     WHERE PRODUCTO = 'Librería');

Primero, la subconsulta encuentra el ID_comprador de la persona(s) que compró la librería, después la


consulta de salida actualiza el apellido.

Recuerda esta regla sobre las subconsultas: cuando tienes una subconsulta como parte de una condición
WHERE, la cláusula Selec en la subconsulta tiene que tener columnas que concuerden en número y tipo con
aquellas que formen parte de la condición WHERE de la subconsulta. En otras palabras, si tienes "WHERE
ColumnName = (SELECT...);", Select debe de tener sólo una columna en ella, para coincidir con la salida en
la cláusula Where, y estas deberán de coincidir en tipo

EXISTS & ALL


 
EXISTS usa una subconsulta como condición, donde la condición es verdadera si la subconsulta devuelve
alguna fila, y falsa si la subconsulta no devuelve ninguna fila; esta es una característica no intuitiva con sólo
algunos usos. Sin embargo, si un empleado quiere ver la lista de Owners sólo si hay sillas disponibles, intenta:

SELECT NOMBREPROPIETARIO, APELLIDOPROPIETARIO


FROM PROPIETARIOS_ANTIGÜEDADES
WHERE EXISTS
    (SELECT *
     FROM ANTIGÜEDADES
     WHERE PRODUCTO = 'Silla');

Si hay alguna silla en la columna Antigüedades, la subconsulta devolverá una o varias filas, haciendo la
cláusula EXISTS verdadera, haciendo que SQL liste los Antique Owners. Si no ha habido sillas, ninguna fila
será devuelta por la subconsulta.

ALL es otra construcción poco usual , como las consultas ALL pueden ser usadas con diferentes y simples
métodos, veamos un ejemplo de consulta:

SELECT ID_COMPRADOR, PRODUCTO


FROM ANTIGÜEDADES
WHERE PRECIO = ALL
    (SELECT PRECIO
     FROM ANTIGÜEDADES);

Esto devolverá el precio de producto más alto (o más de un producto si hay un empate), y su comprador. La
subconsulta devuelve una lista de todos los precios de la tabla Antigüedades, y la consulta de salida va fila por
fila de la tabla Antigüedades y si el precio es mayor o igual a todos (o ALL) precios en la lista, es listado,
dando el precio del producto más caro. La razón de "=" es que el mayor precio en la lista puede ser igual al de
la lista, ya que este producto está en la lista de precios.

 
UNION & Uniones de salida

Hay ocasiones donde puedes querer ver los resultados de múltiples consultas a la vez combinando sus salidas;
usa UNION. Por ejemplo, si queremos ver todos los ID_COMPRADOR de la tabla de Antigüedades junto con
los ID_PROPIETARIO de la tabla de PEDIDOS, usaremos:

SELECT ID_COMPRADOR
FROM ANTIGÜEDADES
UNION
SELECT ID_PROPIETARIO
FROM PEDIDOS;

SQL requiere que la lista de Select (de columnas) coincida, columna por columna, en el tipo de datos. En este
caso ID_comprador y ID_Propietario son del mismo tipo (integer). Además, SQL elimina automáticamente
los duplicados cuando se usa UNION (como si ellos fuera dos "conjuntos"); en las consultas simples, tienes
que usar DISTINCT.

La unión de salida es usada cuando una consulta de unión está "unida" con filas no incluidas en la unión, y
son especialmente útiles si las "flags" son incluidas. Primero observa la consulta:

SELECT ID_PROPIETARIO, 'is in both Pedidos & Antigüedades'


FROM PEDIDOS, ANTIGÜEDADES
WHERE ID_PROPIETARIO = ID_COMPRADOR
UNION
SELECT ID_COMPRADOR, 'is in Antigüedades only'
FROM ANTIGÜEDADES
WHERE ID_COMPRADOR NOT IN
    (SELECT ID_PROPIETARIO
     FROM PEDIDOS);

Esta consulta hace una unión para listar todos los propietarios que están en ambas tablas, y pone una línea
etiqueta después de ID repitiendo la cita. La UNION une esta lista con al siguiente lista. La segunda lista es
generada primero listando aquellos ID que no están en la tabla Pedidos, generando una lista de ID excluidos
de la consulta de unión. Entonces, cada fila en la tabla Antigüedades es escaneada, y si el ID_comprador no
está en esta lista de exclusión, es listado con su cita etiqueta. Debe haber un modo más sencillo de hacer esta
lista, pero es difícil generar la informativa cita de texto.

Este concepto es muy útil en situaciones donde la clave primaria está relacionada con una clave ajena, pero el
valor de la clave ajena para algunas claves primarias es NULL. Por ejemplo, en una tabla, la clave primaria es
vendedor, y en otra tabla es clientes, con el nombre de los vendedores en la misma fila. Sin embargo, si un
vendedor no tiene clientes, el nombre de esta persona no aparecerá en la tabla de clientes. La unión de salida
es usada si el listado de todos los vendedores va ha ser impreso, junto con sus clientes, aunque el vendedor no
esté en la tabla de clientes, pero está en la tabla de vendedores. En otro caso, el vendedor será listado con cada
cliente.

CAPÍTULO 5. SQL EMBEBIDO

SQL embebido

Un feo ejemplo (no escribas un programa como este ...esto es sólo con propósitos educativos)

 /* - Para verlo, aquí tienes un programa ejemplo que usa SQL embebido. SQL embebido permite
a los programadores conectar con una base de datos e incluir código SQL en su programa, y poder usar,
manipular y procesar datos de la base de datos..
- Este ejemplo de programa en C (usando SQL embebido) imprimirá un informe.
- Este programa deberá ser precompilado para las sentencias SQL, antes de la compilación normal.
- Las partes EXEC SQL son las mismas (estándar), pero el código C restante deberá ser cambiado,
incluyendo la declaración de variables si estás usando un lenguaje diferente.
-SQL embebido cambia de sistema a sistema, así que, una vez más, comprueba la documentación,
especialmente la declaración
de variables y procedimientos, en donde las consideraciones del DBMS y el sistema operativo son cruciales.
*/
/* ***************************************************/
/* ESTE PROGRAMA NO ES COMPILABLE O EJECUTABLE */
/* SU PROPOSITO ES SÓLO DE SEVIR DE EJEMPLO             */
/****************************************************/
#include <stdio.h >

/* Esta sección declara las variables locales, estas deberán ser las variables que tu programa use, pero también

las variables SQL podrán ser utilizadas para tomar o dar valores */

EXEC SQL BEGIN DECLARE SECTION;


    int ID_comprador;
    char Nombre[100], Apellidos[100], Producto[100];
EXEC SQL END DECLARE SECTION;
/* Esto incluye la variable SQLCA , aquí puede haber algún error si se compilase. */

EXEC SQL INCLUDE SQLCA;


main() {

/* Este es un posible camino para conectarse con la base de datos */

EXEC SQL CONNECT UserID/Password;

/* Este código informa si estás conectado a la base de datos o si ha habido algún error durante la conexión*/

if(sqlca.sqlcode)
{
    printf(Printer, "Error conectando al servidor de la base de datos.\n");
    exit();
 }
printf("Conectado al servidor de la base de datos.\n");

/* Esto declara un "Cursor". Éste es usado cuando una consulta devuelve más de una fila, y una operación va a
ser realizada en cada fila resultante de la consulta. Con cada fila establecida por esta consulta, lo usare en el
informe. Después "Fetch" será usado para sacar cada fila, una a una, pero para la consulta que está
actualmente ejecutada, se usará el estamento "Open". El "Declare" simplemente establece la consulta.*/

EXEC SQL DECLARE ProductoCursor CURSOR FOR


        SELECT PRODUCTO, ID_COMPRADOR
        FROM ANTIGÜEDADES
        ORDER BY PRODUCTO;

EXEC SQL OPEN ProductoCursor;

 /* +-- Podrías desear poner un bloque de chequeo de errores aquí. --+ */

/* Fetch pone los valores de la "siguiente" fila de la consulta en las variables locales, respectivamente. Sin
embargo, un "priming fetch" (tecnica de programación) debe ser hecha antes. Cuando el cursor está fuera de
los datos, un código SQL debe de ser generado para permitirnos salir del bucle. Para simplificar, el bucle será
dejado cuando ocurra cualquier código SQL, incluso si es una código de error. De otra manera, un código de
chequeo específico debería de ser preparado*/

EXEC SQL FETCH ProductoCursor INTO :Producto, :ID_comprador;

while(!sqlca.sqlcode)
{

/* Con cada fila, además hacemos un par de cosas. Primero, aumentamos el precio $5 (honorarios por
tramitaciones) y extraemos el nombre del comprador para ponerlo en el informe. Para hacer esto, usaremos
Update y Select, antes de imprimir la línea en la pantalla. La actuaclización, sin embargo, asume que un
comprador dado sólo ha comprado uno de todos los productos dados, o sino, el precio será incrementado
demasiadas veces. Por otra parte, una "FilaID" podría haber sido utilizada (ver documentación). Además
observa los dos puntos antes de los nombres de las variables locales cuando son usada dentro de sentencias de
SQL.*/

    EXEC SQL UPDATE ANTIGÜEDADES


    SET PRECIO = PRECIO + 5
    WHERE PRODUCTO = :Producto AND ID_COMPRADOR = :ID_comprador;

    EXEC SQL SELECT NOMBREPROPIETARIO, APELLIDOPROPIETARIO


    INTO :Nombre, :Apellidos
    FROM PROPIETARIOS_ANTIGÜEDADES
    WHERE ID_COMPRADOR = :ID_comprador;

    printf("%25s %25s %25s", Nombre, Apellidos, Producto);


/* Feo informe- sólo para propositos de ejemplo!. Veamos la siguiente fila */
    EXEC SQL FETCH ProductoCursor INTO :Producto, :ID_comprador;
}
/* Cierra el cursor, entrega los cambios (ver debajo), y sale del programa */
EXEC SQL CLOSE ProductoCursor;
EXEC SQL COMMIT RELEASE;
exit();
}

CAPÍTULO 6. Cuestiones Comunes & Tópicos Avanzados

¿Por qué no puede preguntar simplemente por las tres primeras filas de la tabla? Porque en las bases de
datos relacionales, las filas son insertadas en un orden particular, esto es, el sistema las inserta en un orden
arbitrario; así, que sólo puedes pedir filas usando un válida construcción SQL, como ORDER BY, etc.

¿Qué es eso de DDL y DML?. DDL (Data Definition Language) se refiere a (en SQL) a la sentencia de
creación de tabla... DML (Data Manipulation Language) se refiere a las sentencia Select, Update, Insert y
Delete.

¿No son las tablas de las bases de datos como ficheros? Bueno, el DBMS almacena los datos en ficheros
declarados por los administrados del sistema antes de que nuevas tablas son creadas (en grandes sistemas),
pero el sistema almacena los datos en un formato especial, y puede diseminar los datos de una tabla sobre
muchos archivos. En el mundo de la base de datos, un conjunto de archivos creados por la base de datos es
llamado "tablespace". En general, en pequeños sistemas, todos lo relacionado con una base de datos
(definiciones y todo los datos de la tabla) son guardados en un archivo.

¿Són las tablas de datos como hojas diseminadas? No, por dos razones. Primeras, las hojas diseminadas
pueden tener datos en una celda, pero una celda es más que una simple intersección de fila-columna.
Dependiendo del software de diseminación de hojas, una celda puede contener formulas y formatos, los cuales
no pueden ser tenidos por una tabla de una base de datos. Segundo, las celdas diseminadas son usualmente
dependientes de datos en otras celdas. En las bases de datos, las celdas son independientes, excepto que las
columnas estén lógicamente relacionadas (por suerte, una fila de columnas, describe, en conjunto, una
entidad), y, cada fila en una tabla es independiente del resto de filas.

¿Cómo puedo importar un archivo texto de datos dentro de una base de datos? Bueno, no puedes hacerlo
directamente... debes usar una utilidad, como "Oracle’s SQL*Loader", o escribir un programa para cargar los
datos en la base de datos. Un programa para hacerlo simplemente iría de registro en registro de un archivo
texto, dividiéndolo en columnas, y haciendo un Insert dentro de la base de datos.

¿Qué es un esquema? Un esquema es un conjunto lógico de tablas, como la base de datos Antigüedades
arriba... usualmente, se piensa en él simplemente como "la base de datos", pero una base de datos puede
contener más de un esquema. Por ejemplo, un esquema estrella está compuesto de tablas, donde una gran y
central tabla tiene toda la información importante, con la que se accede, vía claves ajenas, a tablas
dimensionales, las cuales tienen información de detalle, y pueden ser usadas en una unión para crear informes
detallados.

¿Hay algún filtro en general que puede usar para hacer mis consultas SQL y bases de datos mejores y más
rápidas (optimizadas)? Puedes intentar, si puedes, evitar expresiones en Selects, tales como SELECT
ColumnaA + Columna B, etc. La consulta optimizada de la base de datos, la porción de la DBMS que
determina el mejor camino para conseguir los datos deseados fuera de la base de datos, tiene expresiones de
tal forma que puede requerir más tiempo recuperar los datos que si las columnas fueran seleccionadas de
forma normal, y las expresiones se manejaran programáticamente.
 Si estas usando una unión, trata de tener las columnas unidas por índices (desde ambas tablas).

 Cuando tengas dudas, índice.

 A no ser que tengas múltiples cuentas o consultas complejas, usa COUNT(*) (el número de filas
generadas por la consulta) mejor que COUNT(Nombre_Columna).
¿Qué es normalización? Normalización es una técnica de diseño de bases de datos que sugiere un cierto
criterio en la construcción del diseño de una tabla (decidir que columnas tendrá cada tabla, y creando la
estructura de claves), donde la idea es eliminar la redundancia de los datos no-claves entre tablas.
Normalización se refiere usualmente a condiciones de forma, y sólo introduciré las tres primeras, aunque es
usual el uso de otras más avanzadas, como la cuarta, quinta, Boyce-Codd...)
 
 La Primera Forma Normal se refiere a mover los datos en diferentes tablas donde los datos de cada
tabla son de tipo similar, dando a cada tabla una clave primaria.

 Poner los datos en la Segunda Forma Normal se refiere a remover a otras tablas datos que sólo
dependen de parte de la clave. Por ejemplo, si hubiera dejado los nombres de antiguos propietarios en
la tabla de productos, esta no estará en la Segunda Forma Normal, porque los datos serán
redundantes; el nombre será repetido para cada producto del que se sea propietario; teniendo en
cuenta que los nombres están almacenados en su propia tabla. Los nombre en si mismos no tienen
nada que hacer con los productos, sólo las identidades de los compradores y vendedores.

 La Tercera Forma Normal involucra deshacerse de todo aquello de las tablas que no dependa
solamente de la clave primaria. Solo incluye información que es dependiente de la clave, y mueve a
otras tablas que son independientes de la clave primaria, y crea claves primarias para las nuevas
tablas.
 Hay alguna redundancia en cada forma, y si los datos están en la 3FN , también lo estarán en la 1FN y en la
2FN, y si lo están en la 2FN, también lo estarán en la 1FN. En términos de diseño de datos, almacenar los
datos, de tal manera, que cualquier columna no-clave primaria esté en dependencia sólo de la entera clave
primaria. Si observas el ejemplo de base de datos, verás que la única forma de navegar através de la base de
datos es utilizando uniones usando columnas clave.
Otros dos importantes puntos en una base de datos es usar buenos, consistentes, lógicos, y enteros nombres
para las tablas y las columnas, y usar nombres completos en la base de datos también. En el último punto, mi
base de datos es falta de nombres, así que uso códigos numéricos para la identificación. Es, usualmente,
mejor, si es posible, tener claves que, por si misma, sea expliquen, por ejemplo, a clave mejor puede ser las
primeras cuatro letras del apellido y la primera inicial del propietario, como JONEB por Bill Jones (o para
evitar redundancias, añadir un número, JONEB1, JONEB2 ...).
 
¿Cuál es la diferencia entre una simple consulta de fila y una múltiple consulta de filas y por qué es
importante conocer la diferencia? Primero, para cubrir lo obvio, una consulta de una sólo fila es una consulta
que sólo devuelve una fila como resultado, y una consulta de múltiples filas es una consulta que devuelve más
de una fila como resultado. Si una consulta devuelva una fila o más esto depende enteramente del diseño (o
esquema) de las tablas de la base de datos. Como escritor de consultas, debes conocer el esquema, estar
seguro de incluir todas las condiciones, y estructurar tu sentencia SQL apropiadamente, de forma que consigas
el resultado deseado (aunque sea una o múltiples filas). Por ejemplo, si quieres estar seguro que una consulta
de la tabla Propietarios_Antigüedades devuelve sólo una fila, considera una condición de igualdad de la
columna de la clave primaria, ID_Propietario.  Tres razones vienen inmediatamente a la mente de por qué
esto es importante. Primero, tener múltiples filas cuando tú sólo esperabas una, o viceversa, puede significar
que la consulta es errónea, que la base de datos está incompleta, o simplemente, has aprendido algo nuevo
sobre tus datos. Segundo, se estás usando una sentencia Update o Delete, debes de estar seguro que la
sentencia que estás escribiendo va a hacer la operación en la fila (o filas) que tú quieres... o sino, estarás
borrando o actualizando más filas de las que querías. Tercero, cualquier consulta escrita en SQL embebido
debe necesitar ser construida para completar el programa lógico requerido. Si su consulta, por otra parte,
devuelve múltiples filas, deberás usar la sentencia Fetch, y muy probablemente, algún tipo de estructura de
bucle para el procesamiento iterativo de las filas devueltas por la consulta.
¿Qué hay de las relaciones? Otra cuestión de diseño... el término "relaciones" usualmente se refiere a las
relaciones entre claves ajenas y primarias entre tablas. Este concepto es importante porque cuando las tablas
de una base de datos relacional es diseñada, estas relaciones debe de ser definidas porque determinan que
columnas son o no claves primarias o claves ajenas. Debes de haber oido algo sobre el Diagrama de Entidad-
Relación, que es una vista gráfica de las tablas en el esquema de una base de datos, con líneas conectando
columnas relacionadas entre tablas. Mira el diagrama en el final de esta sección o algunos de los sitios debajo
relacionados con éste tópico, ya que hay diferentes maneras de dibujar diagramas de E-R. Pero primero,
veamos cada tipo de relación ...

 Una relación Uno-a-Uno significa que tu tienes una columna clave primaria que está relacionada
con una columna clave ajena, y que para cada valor de la clave primaria, hay un valor de clave ajena.
Por ejemplo, en el primer ejemplo, la EmployeeAddressTable, nosotros añadimos una columna
ID_EMPLEADO. Entonces, la EmployeeAddressTable está relacionada con la
Tabla_estadistica_empleados (segundo ejemplo de tabla) por medio de este ID_EMPLEADO.
Específicamente, cada empleado en la EmployeeAddressTable tiene estadísticas (un fila de datos) en
la Tabla_estadistica_empleados. Incluso, piensa que este es un ejemplo efectuado, es una relación de
"1-1". Además, ten en cuenta, el "tiene" en fuerte... cuando se expresa una relación, es importante
describir la relación con un verbo.

 Las otras dos tipos de relaciones pueden o no puede usar claves primarias lógicas y claves ajenas
necesariamente... esto es estrictamente una llamada del sistema. La primera de éstas es la relación
Uno-a-Muchos ("1-M"). Esto significa que para cada valor de la columna en una tabla, hay uno o
más valores relaciones en otra tabla. Habrá que añadir de forma necesaria claves en el diseño o,
posiblemente, algún tipo de columna identificador deberá ser usado para establecer la relación. Un
ejemplo podría ser que para todos ID_Propietario en la tabla Propietarios_Antigüedades, hubierán
uno o mas (cero también pude ser) productos comprados en la tabla Antigüedades (verbo: comprar).

 Finalmente, la relación de Muchos-a-Muchos ("M-M") generalmente no involucra claves, y


usualmente involucra columnas identificativas. La inusual ocurrencia de un "M-M" significa que una
columna en una tabla está relacionada con otra columna en otra tabla, y para cada valor de uno de
estas dos columnas, hay uno o más valores relacionados en la correspondiente columna en la otra
tabla (y viceversa), o más comúnmente posible, dos tablas tienen una relación "1-M" para cada una
(dos relaciones, una 1-M para cada camino). Un (malo) ejemplo o ésta más común situación podría
ser si tuvieras una base de datos que asignara trabajo, donde una tabla tuviera una fila por cada
empleado y trabajo asignado, y otra tabla tuviera una fila por trabajo por cada uno de los trabajadores
asignados. Aquí, podrías tener múltiples filas por cada empleado en la primera tabla, o pro cada
trabajo asignado, y múltiples filas por cada trabajo en la segunda tabla, una por empleado asignado al
proyecto. Estas tablas tienen un M-M: cada empleado en la primera tabla puede tener tantos trabajos
asignados de la segunda tabla como trabajos haya en ella, y cada trabajo puede tener tanto empleados
como empleados haya en la primera tabla. Esto es la punta del iceberg en este tópico... mira los links
abajo para más información y mira en diagrama de debajo para un ejemplo simplificado de un
diagrama de E-R.
 
¿Qué hay de algunas construcciones no estándar importantes de SQL (pregunta extremadamente común)?
Bueno, veamos la siguiente sección...

CAPÍTULO 7. SQL no estándar

 
 
INTERSECT yMINUS son como la sentencia UNION, excepto que INTERSECT produce filas que apareces
en ambas consultas, y MINUS produce filas que resultan de la primera consulta, pero no de la segunda.

Generación de construcciones de informe: la cláusula COMPUTE es puesta al final de una consulta para


poner el resultado en una función agregada al final del listado, como COMPUTE SUM(PRECIO); Otra opción
es usar el break lógico: definir un break para dividir un resultado de una consulta dentro de grupos basados en
una columna, como BREAK ON ID_COMPRADOR. Entonces, para producir un resultado después de listar
un grupo, usa COMPUTE SUM OF PRECIO ON ID_COMPRADOR. Si, por ejemplo, usas las tres cláusulas
juntas (BREAK primero, COMPUTE después del BREAK, y COMPUTE sobre todo ), obtendrás un informe
que agrupe los productos por su ID_comprador, listando la suma de Precios después de cada grupo de
productos de un ID_comprador, y , después que todos los grupos sean listados, la suma de todos los Precios
listados, todos con cabeceras y líneas generados por SQL.

Además, algunos DBMS permiten usar más funciones en listas Select, excepto que estas funciones (algunas
funciones de carácter permite resultados de múltiples filas) vayan a ser usadas con un valor individual (no
grupos), en consultas de simples filas. Las funciones deben ser usada sólo con tipos de datos apropiados. Aquí
hay algunas funciones Matemáticas:

         Funciones numéricas:


 
ABS(X) Valor absoluto. Convierte número negativos en positivos, o deja sólo números positivos. 
CEIL(X) X es un valor decimal que será redondeado hacia arriba.
FLOOR(X) X es un valor decimal que será redondeado hacia abajo.
GREATEST(X,Y) Devuelve el más grande de los dos valores.
LEAST(X,Y) Devuelve el más pequeño de los dos valores.
MOD(X,Y) Devuelve el resto de X/Y.
POWER(X,Y) Devuelve X elevado a Y
ROUND(X,Y) Redondea X a Y lugares decimales. Si se omite Y, X se redondea al entero más próximo.
SIGN(X) Devuelve menos si X<0, sino un más.
SQRT(X) Devuelve la raiz cuadrada de X.

           Funciones de Caracteres


 
LEFT(<string,X) Devuelve los X caracteres más a la izquierda de la cadena.
RIGHT(<string,X) Devuelve los X caracteres más a la derecha de la cadena.
UPPER(<string) Convierte la cadena a mayúsculas.
LOWER(<string) Convierte la cadena a minúsculas.
INITCAP(<string) Convierte el primer carácter de la cadena a mayúscula.
LENGTH(<string) Devuelve el número de carácteres de cadena.
<string||<string Concatena dos cadenas de texto.
Rellena la cadena por la izquierda con el * (o el carácter que haya entre las comillas), para hacer la
LPAD(<string,X,'*')
cadena X caracteres más larga.
Rellena la cadena por la derecha con el * (o con el carácter que haya entre las comillas), para hacer
RPAD(<string,X,'*')
la cadena X caracteres más larga.
SUBSTR(<string,X,Y) Extrae Y letras de la cadena comenzando en la posición X.
Cualquier Null de la <column será sustituido por lo que haya en <value. Si el valor de la columna no
NVL(<column,<value)
el NULL, NVL no tiene efecto

CAPÍTULO 8. Resumen de Sintaxis & Links importantes

Resumen de Sintaxis. Sólo para usuarios avanzados.


Aquí están las formas generales de las sentencias que hemos visto en este tutorial, además de alguno
información extra de algunas. RECUERDA que todos estas sentencias pueden o no pueden estar disponibles
en tu sistema, así que comprueba la documentación del mismo.

ALTER TABLE <TABLE NAME ADD|DROP|MODIFY (COLUMN SPECIFICATION[S]...ver


Create Table);

Te permite añadir, borrar o modificar una columna o columnas de la tabla, o cambiar la especificación (tipo
de datos, etc) de una columna existente; esta sentencia también es usada para las especificaciones físicas de la
tabla (como está almacenada, etc.), pero estas definiciones estas especificadas en el DBMS, así que léete la
documentación. También, estas especificaciones físicas son usada con la sentencia Create Table, cuando una
tabla es creada por primera vez. Además, solo una opción puede ser realizada por la sentencia Alter Table en
una simple sentencia: add, drop o modificar.

COMMIT;

Hace cambios hechos por algún sistema permanente de base de datos (desde el último COMMIT; conocido
por transacción)
 
CREATE [UNIQUE] INDEX <INDEX NAME
ON <TABLE NAME (<COLUMN LIST); --UNIQUE es opcional; entre corchetes.

 CREATE TABLE <TABLE NAME


(<COLUMN NAME <DATA TYPE [(<SIZE)] <COLUMN CONSTRAINT,
...otras columnas; (también valido con ALTER TABLE)
--donde SIZE sólo se utiliza en determinados tipos, y CONSTRAIN incluye las siguientes posibilidades
(forzado automático por la DBMS; causas de fallos y generación de errores):

1.NULL o NOT NULL (ver arriba)

2.UNIQUE fuerza que dos filas no puedan tener el mismo valor para esa columna.

3.PRIMARY KEY le dice a la base de datos que la columna es la columna clave primaria (sólo usado si la
clave primaria es sólo un columna, sino, la sentencia PRIMARY KEY(columna, columna,...) aparece después
de la definición de la última columna)

4.CHECK permite que se comprueba una condición cuando un dato es esa columna es actualizado o
insertado; por ejemplo, CHECK(PRECIO 0), hace que el sistema compruebe que el precio de la columna es
mayor de cero antes de aceptar el valor... algunas veces implementado como  sentencia CONSTRAINT.

5.DEFAULT inserta el valor por defecto en la base de datos si una fila es insertada sin insertar ningún dato en
la columna; por ejemplo: BENEFICIOS INTEGER DEFAULT=10000;

6.FOREIGN KEY hace lo mismo que la clave primaria, pero es seguida por:: REFERENCES <TABLE
NAME (<COLUMN NAME), que hacen referencia a la clave primaria relacionada.
 
CREATE VIEW <TABLE NAME AS <QUERY;

DELETE FROM <TABLE NAME WHERE <CONDITION;

INSERT INTO <TABLE NAME [(<COLUMN LIST)]


VALUES (<VALUE LIST);

ROLLBACK; --deshace los cambios en la base de datos que hallas hecho desde el último Commit...
cuidado! Algunos software usan automáticamente Commit’s en sistemas que usan construcciones de
transacción, así que el comando RollBack podría no ir.

SELECT [DISTINCT|ALL] <LISTA DE COLUMNAS, FUNCTIONES, CONSTANTES, ETC.


FROM <LISTA DE TABLAS OR VISTAS
[WHERE <CONDICION(S)]
[GROUP BY <GROUPING COLUMN(S)]
[HAVING <CONDITION]
[ORDER BY <ORDERING COLUMN(S) [ASC|DESC]]; --donde ASC|DESC permite ordenas en orden
ASCendente o
DESCendente

UPDATE <TABLE NAME


SET <COLUMN NAME = <VALUE
[WHERE <CONDITION]; - si no se completa la cláusula Where, todas las filas serán actualizadas de
acuerdo con la sentencia SET.

SQL (Server Query Language)

LMD (Lenguaje de Manipulación de Datos)


SELECT

SELECT [DISTINCT] <lista_columnas> | *


FROM <lista_tablas>
[WHERE <predicado>]

EJ: Visualizar todos los vuelos que tengan como origen o destino Cáceres.

SELECT *
FROM VUELOS
WHERE ORIGEN='CACERES'
OR DESTINO='CACERES'

EJ: Visualizar todos los vuelos que tengan como origen Madrid o Londres y como destino Londres o
Madrid.

SELECT *
FROM VUELOS
WHERE (ORIGEN='MADRID'
AND DESTINO='LONDRES')
OR (ORIGEN='LONDRES'
AND DESTINO='MADRID')

Claúsula IN

Expresa la pertenencia del valor de una columna a un determinado conjunto de valores.

EJ: Seleccionar aquellos vuelos que tengan como origen Madrid, Barcelona o Sevilla.

SELECT *
FROM VUELOS
WHERE ORIGEN IN ('MADRID','BARCELONA','SEVILLA')

ó también

SELECT *
FROM VUELOS
WHERE ORIGEN='MADRID' OR ORIGEN='BARCELONA' OR ORIGEN='SEVILLA'

EJ: Visualizar todos los vuelos existentes excepto aquellos que llegan a Londres o a Copenhague.

SELECT *
FROM VUELOS
WHERE DESTINO NOT IN ('LONDRES','COPENHAGUE')

Claúsula BETWEEN

Sirve para establecer o expresar un rango de valores. Obedece a la siguiente sintaxis:

<nombre_columna> BETWEEN valor1 AND valor2

El rango será [valor1, valor2], extremos incluidos.


EJ: Recuperar todos los vuelos que salgan entre las 6 y las 12 de la mañana.

SELECT *
FROM VUELOS
WHERE HORA_SALIDA BETWEEN '06.00.00'
AND '12.00.00'

ó también
SELECT *
FROM VUELOS
WHERE HORA_SALIDA >= '06.00.00'
AND HORA_SALIDA <= '12.00.00'

EJ: En la columna NUM_VUELO representaré los vuelos con 6 caracteres. Los dos primeros caracteres
indicarán la compañía a la que pertenece cada vuelo (IB Iberia, BABritish Airways), los cuatro
caracteres siguientes corresponderán al número de vuelo. Bajo estas condiciones recupérense todos los
vuelos que no pertenecen a IBERIA.

SELECT *
FROM VUELOS
WHERE NUM_VUELO NOT BETWEEN 'IB0000'
AND 'IB9999'

Claúsula LIKE

Sirve para especificar, con la ayuda de metasímbolos, cadenas de caracteres que comparten ciertos
caracteres en común. Los metasímbolos que serán utilizados son:

% Equivale a una cadena de caracteres de longitud comprendida entre 0 y n.


'AB%' AB, ABCDE, AB 497

_ Equivale a un único carácter


'A_B' A B, A4B, AJB

EJ: Recuperar todos los vuelos pertenecientes a la compañía IBERIA.

SELECT *
FROM VUELOS
WHERE NUM_VUELOS LIKE 'IB%'

ó también

SELECT *
FROM VUELOS
WHERE NUM_VUELOS LIKE 'IB_ _ _ _'

Expresiones aritméticas
+, -, *, /
Pueden ser utilizadas tanto después de SELECT como después de WHERE. En el primer caso trabajarían
sobre columnas y en el segundo sobre filas.

EJ: Visualizar la longitud y la envergadura de todos los aviones, expresando las magnitudes en pies (en
la base de datos está almacenado en metros, para pasar 1 metro a pies se ha de multiplicar por 3.28), y
la velocidad de crucero en mph(está en Km/h, habrá que dividir por 1.6).

SELECT LONGITUD*3.28, ENVERGADURA*3.28, VELO_CRUC/1.6


FROM AVIONES

┌──┐ ┌──┐ ┌──┐


Etiquetas  └──┘ └──┘ └──┘
-------- -------- -------
-------- -------- -------
-------- ------- ------

En DB/2 de IBM las etiquetas toman los nombres de las columnas (col1, col2, col3)
En SQL-SERVER las etiquetas quedarían así (LONGITUD*3.28, ENVERGADURA*3.28, VELO_CRUC/1.6)

EJ: Relación entre la longitud y la envergadura de todos los aviones.

SELECT LONGITUD/ENVERGADURA
FROM AVIONES

EJ: Seleccionar aquellos aviones cuya longitud supere a su envergadura en más de un 10%.

SELECT *
FROM AVIONES
WHERE LONGITUD > ENVERGADURA*1.10

Funciones de columna

Son funciones que operan con todas las filas que cumplen la condición expuesta en la claúsula WHERE.
Su resultado es un único valor. Sintaxis:

1º) <f_columna> ([DISTINCT] <nombre_columna>)


2º) <f_columna> (<expresión>), donde <expresión> es una expresión aritmética en la cual debe
participar, al menos, una columna.
3º) COUNT(*)

Funciones

<f_columna>:

MIN: Calcula el valor mínimo de una columna.


MAX: Calcula el valor máximo de una columna.
AVG: Calcula la media aritmética de una columna.
SUM: Calcula la suma de todos los campos de una columna.
COUNT: Cuenta el nº de filas de una columna.

A B

3 5

2 8

3 7

4 3

COUNT(A)=COUNT(B)
COUNT(A)=4, COUNT(B)=4
El COUNT de dos columnas de una misma tabla es igual. COUNT(*) sirve para obtener el nº de filas.
EJ: Seleccionar los valores mínimo y máximo de la columna que almacena las velocidades de crucero.

SELECT MIN(VELO_CRUC), MAX(VELO_CRUC)


FROM AVIONES

EJ: Averiguar a que hora parte el primer vuelo hacia Madrid.

SELECT MIN (HORA_SALIDA)


FROM VUELOS
WHERE DESTINO='MADRID'
Regla que cumplen las funciones de columna

La función de columna sólo podrá especificarse detrás de la particula SELECT o en la claúsula HAVING,
pero nunca dentro de la claúsula WHERE.

EJ: Se desea saber cuál es el vuelo que tiene la mínima hora de salida.

SELECT *
FROM VUELOS
WHERE HORA_SALIDA=(SELECT MIN(HORA_SALIDA)
FROM VUELOS)

Claúsula GROUP BY-HAVING

Sirve para dividir una tabla en grupos de filas que comparten características comunes. La sintaxis es:

SELECT <lista_columnas>, <funciones_de_columna>


FROM <lista_tablas>
[WHERE <predicado>]
[GROUP BY <lista_columnas>]
[HAVING <predicado>]

EJ: Efectúese una SELECT que visualice el mínimo valor de hora de salida para cada uno de los
diferentes destinos.

SELECT DISTINCT DESTINO


FROM VUELOS

SELECT MIN(HORA_SALIDA)
FROM VUELOS
WHERE DESTINO LIKE '%'

A continuación se muestra un ejemplo de lo que no se debe hacer:

SELECT MIN(HORA_SALIDA)
FROM VUELOS
WHERE DESTINO IN (SELECT DISTINCT DESTINO
FROM VUELOS)

Sentencia GROUP BY:

SELECT DESTINO, MIN(HORA_SALIDA)


FROM VUELOS
GROUP BY DESTINO

Tabla VUELOS  Tabla auxiliar  Tabla x 'MADRID '


WHERE GROUP BY DESTINO Tabla y 'BARCELONA'
Tabla z 'SEVILLA'
<f_columna>

GROUP BY crea una serie de subtablas compuestas por filas con el mismo valor para la columna de
agrupamiento (en este ejemplo la columna DESTINO). Se aplicarán a continuación funciones de columna
sobre cada subtabla de forma independiente.

MADRID, x
BARCELONA, y
SEVILLA, z
No se puede poner en GROUP BY un campo que no se haya incluido en la sentencia SELECT.

EJ: Obtener el origen del vuelo para cada uno de los vuelos que tienen la mínima hora de salida para
cada uno de los destinos.

EJ: Obtener el número de vuelos que existen para cada uno de los orígenes.

SELECT ORIGEN, COUNT(*)


FROM VUELOS
GROUP BY ORIGEN

Claúsula HAVING

Permite elegir aquellos grupos que se quieren visualizar.

EJ: Visualizar los grupos que tienen para cada uno de los orígenes la mínima hora de salida siendo
anterior a las 12 horas.

SELECT ORIGEN, MIN(HORA_SALIDA)


FROM VUELOS
GROUP BY ORIGEN
HAVING MIN(HORA_SALIDA) < '12.00'

HAVING no interferirá en la agrupación por filas de GROUP BY.

EJ: Se desea seleccionar la hora de salida más temprana para cada origen y destino.

SELECT ORIGEN, DESTINO, MIN(HORA_SALIDA)


FROM VUELOS
GROUP BY ORIGEN, DESTINO

EJ: Visualizar los orígenes que tengan más de dos vuelos.

SELECT ORIGEN
FROM VUELOS
GROUP BY ORIGEN
HAVING COUNT(*) > 2

EJ: Visualizar los vuelos de IBERIA que tengan más de 150 plazas libres.

SELECT NUM_VUELO, SUM(PLAZAS_LIBRES)


FROM RESERVAS
GROUP BY NUM_VUELO
HAVING NUM_VUELO LIKE 'IB%'
AND SUM(PLAZAS_LIBRES)>150

ó también

SELECT NUM_VUELO, SUM(PLAZAS_LIBRES)


FROM RESREVAS
WHERE NUM_VUELO LIKE 'IB%'
GROUP BY NUM_VUELO
HAVING NUM_VUELO 'IB%'
AND SUM(PLAZAS_LIBRES)>150

TRATAMIENTO DE NULOS

Operaciones aritméticas

Cualquier operación aritmética sobre un campo nulo nos devolverá como resultado un valor nulo.
Tomemos como ejemplo la siguiente tabla:

NULOS

COL_A COL_B

15 10

35 35

140 NULL

NULL 100

NULL NULL

7 110

33 60

NULL NULL

NULL NULL

SELECT COL_A+COL_B
FROM NULOS

COL_A+COL_B
25
70
NULL
NULL
NULL
117
93
NULL
NULL
Funciones de columna

Ignoran los campos NULL, exceptuando la función COUNT.

SELECT AVG(COL_A)
SELECT SUM(COL_A)/COUNT(*)

AVG(COL_A)=46
SUM(COL_A)/COUNT(*)=25.5

Comparaciones

Dos valores nulos no son iguales ni son distintos, sino indeterminados.


SELECT *
FROM NULOS
WHERE COL_A=COL_B

COL_A COL_B
35 35

SELECT *
FROM NULOS
WHERE COL_A<>COL_B

COL_A COL_B
15 10
140 NULL
NULL 100
7 110
33 60

SELECT *
FROM NULOS
WHERE COL_A IS NULL

Esta orden visualiza todas las filas en las que el campo perteneciente a la columna COL_A es nulo.

Ordenación

Dependiendo del sistema gestor en uso los valores nulos serán los de mayor o los de menor peso.

DB/2 de IBM

NULL  Mayor peso. en ordenación ascendente serán los últimos.

SELECT COL_A
FROM NULOS
ORDER BY COL_A

COL_A
7
15
33
35
140
NULL
NULL
NULL
NULL
SQL-SERVER

NULL  Menor peso. En ordenación ascendente serán los primeros.

SELECT COL_A
FROM NULOS
ORDER BY COL_A

COL_A
NULL
NULL
NULL
NULL
7
15
33
33
140

DISTINCT

No elimina los valores nulos repetidos.

SELECT DISTINCT COL_A


FROM NULOS

COL_A
15
35
140
NULL
NULL
7
33
NULL
NULL

Indices únicos

Sobre una columna de índice único sólo está permitida la existencia de un valor nulo.

CREATE UNIQUE INDEX IXNULOS


ON NULOS
(COL_A)

Devolvería un error, ya que existe más de un campo con NULL.


Para este caso los nulos se interpretan como valores iguales.

GROUP BY

Todos los nulos quedarán agrupados en el mismo grupo.

SELECT COL_A, COUNT(*)


FROM NULOS
GROUP BY COL_A

COL_A COUNT(*)
15 1
35 1
140 1
NULL 4
7 1
33 1

Todos los valores NULL se agrupan y COUNT devuelve el número de filas que tenían NULL en COL_A.

SUBSELECT

Responde a la siguiente sintaxis:

SELECT <lista_columnas>
FROM <lista_tablas>
WHERE <nombre_columna> <CONCATENADOR> (SELECT <nombre_columna>
FROM <lista_tablas>
WHERE <Predicado>)

<CONCATENADOR>

Puede ser un operador de comparación o la claúsula IN


Operadores de comparación: >,<,>=,<=,=,<>

Restricciones: ha de exigirse que el resultado de la Subselect sea un único valor al usar como
concatenador un operador de comparación. Si usamos IN puede devolver más de un valor.

Cada Select se ejecuta una única vez, desde la más interna, hasta la más externa.

EJ: Se desea recuperar las plazas libres que hay en cada vuelo MADRID-LONDRES del día 20/02/92.

{Las plazas libres es un campo de la tabla de reservas. En la tabla de vuelos tenemos el origen y el
destino de cada vuelo.}

SELECT *
FROM RESERVAS
WHERE FECHA_SALIDA='20.02.1992'
AND NUM_VUELO IN(SELECT NUM_VUELO
FROM VUELOS
WHERE ORIGEN='MADRID'
AND DESTINO='LONDRES')

ANY, ALL

Se usan para poder utilizar operadores de comparación con subselects que nos devuelvan más de un
valor único como resultado.

SELECT <lista_columna>
FROM <lista_tablas>
WHERE <nombre_columna> <CONCATENADOR> {ANY/ALL} (<Subselect>)

Una expresión ANY es cierta si lo es para algún valor de los que devuelve la Subselect.
Una expresión ALL es cierta si lo es para todos los valores que devuelve la Subselect.
3>ANY(2,5,7)  Cierto
3=ANY(2,5,7)  Falso
3>ALL(2,5,7)  Falso
3<ALL(9,10,11)  Cierto

EJ: Se quiere recuperar los aviones cuya longitud sea mayor que la envergadura de todos ellos.

SELECT *
FROM AVIONES
WHERE LONGITUD > ALL (SELECT ENVERGADURA
FROM AVIONES)

ó también

SELECT *
FROM AVIONES
WHERE LONGITUD > (SELECT MAX(ENVERGADURA)
FROM AVIONES)

=ANY e IN tienen la misma función.

3=ANY(2,3,5) y 3 IN (2,3,5) devuelven ambos Cierto.

Subselects correlacionadas

Son un tipo especial de subselect. La sintaxis es similar:

SELECT <lista_columnas>
FROM <nombre_tabla_externa>
WHERE <nombre_columna> <CONCATENADOR> (SELECT <nombre_columna>
FROM <nombre_tabla_interna>
WHERE <Predicado>)

En <Predicado> habrá una sentencia del tipo

<nombre_columna_tabla_interna> <operador> <nombre_columna_tabla_externa>

Las formas de ejecutar una subselect ordinaria y una correlacionadas son diferentes. Las subselects
correlacionadas obedecen al siguiente algoritmo:

ALGORITMO Subselect_Correlacionada
1 Seleccionar fila de tabla externa
2 Ejecutar SELECT interno
3 Evaluar la condición del WHERE externo
- Cierto: la fila seleccionada en 1 será una fila de salida
4 Si existe alguna fila más en la tabla externa ir al paso 1

EJ: Se desea recuperar las reservas cuyo número de plazas libres sea mayor que la media para ese
mismo vuelo.

SELECT *
FROM RESERVAS, A
WHERE PLAZAS_LIBRES > (SELECT AVG(PLAZAS_LIBRES)
FROM RESERVAS
WHERE NUM_VUELO=A.NUM_VUELO)

RESERVAS

NUM_VUELO FECHA_SALIDA PLAZAS_LIBRES

IB740 20.02.92 5
IB740 25.02.92 15
IB740 03.03.92 10

AVG(PLAZAS_LIBRES)=10

Alias

Es un sobrenombre que se le da a una tabla y que debe ser único para toda la consulta. Se escribe
dejando un blanco detrás del nombre de la tabla a la cual se va a calificar.

EJ: Se quiere recuperar los aviones que tienen menos de 1 hora y cuarto de recorrido como término
medio.
VUELOS

NUM_VUELO ORIGEN DESTINO DISTANCIA

B747 MADRID LONDRES 10000


B747 MADRID PARIS 4000

AVIONES

NUM_VUELO VELO_CRUC

............ ............

v=e/t, t>e/v, 1.25>e/v, v*1.25 > AVG(DISTANCIA)


SELECT AVIONES SELECT VUELOS

SELECT *
FROM AVIONES
WHERE 1.25*VELO_CRUC > (SELECT AVG(DISTANCIA)
FROM VUELOS
WHERE NUM_VUELO=AVIONES.NUM_VUELO)

EXISTS-NOT EXISTS

Se define para comprobar la existencia o ausencia del valor devuelto por una Subselect. Una expresión
con EXIST devuelve Cierto si la Subselect nos devuelve al menos un valor.

WHERE EXISTS (<Subselect>)  Cierto

EJ: Seleccionar toda la información de vuelos para aquellos que tengan origen Madrid y en los que
queden plazas libres.

SELECT *
FROM VUELOS
WHERE ORIGEN='MADRID'
AND EXISTS (SELECT *
FROM RESERVAS
WHERE PLAZAS_LIBRES > 0
AND NUM_VUELO=VUELOS.NUM_VUELO)

EJ: Obtener los tipos de avión y capacidades para aquellos en los que queden menos de 30 plazas libres
(JOIN).

ORDER BY

Se define para ordenar la salida de una consulta por los campos que se especifiquen a continuación.

Sintaxis:

SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY

ORDER BY <especificación de columna><orden>{,<especificación de columna><orden>}

<especificación de columna>=<nombre de columna>|<posición de columna>


<orden>=ASC|DESC
Ej: Obtener el número de plazas libres que quedan para cada vuelo y ordenar el resultado de más a
menos plazas libres. Para igual número de plazas ordénese por número de vuelo.

SELECT NUM_VUELO, SUM(PLAZAS-LIBRES)


FROM RESERVAS
GROUP BY NUM_VUELO
ORDER BY 2 DESC, NUM_VUELO

UNION-UNION ALL

Se define para recuperar, usando una única consulta, información que se obtiene a partir de más d una
consulta.

Sintaxis:

<SELECT>
UNION [ALL]
<SELECT>
{UNION[ALL]
<SELECT>}

Características:

Cada SELECT devuelve un conjunto de filas. La unión será la tabla resultado.

Condiciones de cada estructura SELECT:

- Todas deben ser iguales o compatibles una a una. Esto supone que por cada columna tengamos un
único tipo de dato.

- Pueden ser completas (WHERE, GROUP BY, ...), exceptuando la claúsula ORDER BY, que se ubicará al
final de la última SELECT.

UNION sin ALL proporciona un resultado sin filas duplicadas.

Ej: Sacar una lista de todas aquellas ciudades para las que haya vuelo, ordenadas alfabéticamente.

SELECT ORIGEN
FROM VUELOS
UNION
SELECT DESTINO
FROM VUELOS
ORDER BY 1

Catálogo del sistema o diccionario de datos:

Es el alma de un sistema gestor. Se define como un conjunto de tablas que forman una base de datos, y
son definidas y mantenidas automáticamente por el sistema gestor. Sirven para almacenar información
sobre los objetos definidos por los usuarios.

SELECT *
FROM VUELOS

1- El sistema busca en el catálogo si existe la tabla VUELOS.


2- Verifica si el usuario tiene acceso a esa información.
3- Se pregunta cuáles y cuántas columnas tiene la tabla VUELOS.
DB2 IB
SYSTABLES: una fila por cada tabla definida en la instalación.
SYSCOLUMNS: una fila por cada columna definida.
SYSINDEXES: una fila por cada índice definido.
SYSVIEW: una fila por cada vista.
SYSTABAUTH: una fila por cada autorización definida.

Todas las tablas son directamente consultadas por usuarios autorizados.


ADM (Administrador): es la persona que concede autorizaciones a los usuarios.
Un usuario autorizado puede efectuar operaciones del tipo:

SELECT *
FROM SYSTABLES
WHERE NAME='RESERVAS'

NAME DBNAME CARD


RESERVAS AEROPUERTO ..........

DBNAME: Nombre de la BdD a la que pertenece la tabla.


CARD: Nº de filas de la tabla.
OWNER: Usuario creador de la tabla.

SELECT *
FROM SYSCOLUMNS
WHERE DBNAME='RESERVAS'

Nos da la información sobre todas las columnas que pertenecen a la tabla reservas.

NAME TBNAME COL_NO COL_TYPE LENGTH NULLS


NUM_VUELO RESERVAS 1 CHAR 6 N
FECHA_SALIDA RESERVAS 2 DATE 8 N

TBNAME: Nombre de la tabla.


COL_NO: Posición de la columna en la tabla.
COL_TYPE: Tipo de dato
LENGTH: Longitud del dato de la columna.
NULLS: Indica si se permite valor nulo.
Ej: Obténgase la última hora de salida para cada destino de los vuelos realizados por aviones
capaces de almacenar más combustible que un tercio de la media que pueden almacenar los demás
aviones.

SELECT DESTINO, MAX(HORA_SALIDA)


FROM VUELOS
WHERE TIPO_AVION IN (SELECT TIPO
FROM A
WHERE COMBUSTIBLE>1/3*(SELECT AVG(COMBUSTIBLE)
FROM AVIONES
WHERE TIPO<>A.TIPO)

Ej: Crear una vista sobre la tabla vuelos con las columnas ORIGEN y DESTINO para aquellos vuelos
que no sean de IBERIA. Visualizar el contenido de la lista para los vuelos que no partan de Madrid.
Borrar la vista.

CREATE VIEW V_VUELOS


(V_ORIGEN, V_DESTINO)
AS SELECT ORIGEN, DESTINO
FROM VUELOS
WHERE NUM_VUELO NOT LIKE 'IB%'

SELECT *
FROM V_VUELOS
WHERE V_ORIGEN<>'MADRID'

DROP VIEW V_VUELOS

Ej: Visualice los tipos de avión , el doble de su longitud y la mitad de su envergadura, para aquellos
aviones con envergadura mayor que la media y que realizan vuelos desde o hacia Barcelona,
ordenándolos de mayor a menor longitud.

SELECT TIPO_AVION, 2*LONGITUD, .5*ENVERGADURA


FROM AVIONES, VUELOS
WHERE ENVERGADURA>(SELECT AVG(ENVERGADURA)
FROM AVIONES)
AND
AVIONES.TIPO_AVION=VUELOS.TIPO_AVION
AND
(ORIGEN='BARCELONA' OR DESTINO='BARCELONA)
ORDER BY 2 DESC

Ej: Visualice las tres primeras letras de los orígenes y destinos de los vuelos realizados por aviones
con longitud mayor con longitud mayor que la media y envergadura menor que 2/3 de la máxima
envergadura, ordenados alfabéticamente por destino.

SUBSTRING (SQL)
(SUBSTRNG), (DB2)

SUBSTRING (string, posición, nºcaracteres)



nom_col / cadena con comillas (")

SELECT SUBSTRING (ORIGEN, 1, 3), SUBSTRING (DESTINO, 1, 3)


FROM VUELOS
WHERE TIPO_AVION IN (SELECT TIPO
FROM AVIONES
WHERE LONGITUD > (SELECT AVG(LONGITUD)
FROM AVIONES)
AND ENVERGADURA*3/2 < (SELECT MAX(ENVERGADURA)
FROM AVIONES)
ORDER BY 2

Ej: Visualice el total de plazas libres por número de vuelo para aquellos realizados desde Madrid a
Barcelona o Sevilla y que recorran una distancia mayor que la media de todos los vuelos que salen
de Madrid, ordenándolos de menor a mayor.
SELECT SUM(PLAZAS_LIBRES), NUM_VUELO
FROM RESERVAS, VUELOS
WHERE RESERVAS, NUM_VUELO=VUELOS.NUM_VUELO
AND ORIGEN='MADRID'
AND DESTINO IN ('BARCELONA', 'SEVILLA')
AND DISTANCIA > (SELECT AVG(DISTANCIA)
FROM VUELOS
WHERE ORIGEN='MADRID')
ORDER BY 1

Ej: Obtener para cada número de vuelo el total de plazas libres de los vuelos que recorran
distancias menores que 2/3 de la media de las distancias recorridas por vuelos de otras compañías.

SELECT NUM_VUELOS, SUM(PLAZAS_LIBRES)


FROM RESERVAS, VUELOS  V
WHERE RESERVAS.NUM_VUELO=VUELOS.NUM_VUELOS
AND DISTANCIA*3/2 < (SELECT AVG(DISTANCIA)
FROM VUELOS
WHERE SUBSTRING (NUM_VUELO, 1, 2) <>
SUBSTRING (VUELOS.NUM_VUELO, 1, 2)
TEORIA DE LA NORMALIZACION

Introducción:

Nos basaremos en la siguiente tabla:

AUTORES-LIBROS

NOMBRE NACION COD_LIB TITULO EDITOR

Date USA 999 IBD AW

Ad.Mig. ESP 888 CyD RM

Ma.Piat. ITA 888 CyD RM

Date USA 777 BdD AW

Bibliografía: DIseño y Gestión de Bases de Datos. Angle Lucas.

Se plantean una serie de problemas:

Redundancia: cuando un autor tiene varios libros, se repite la nacionalidad.

Anomalías de modificación: Si Ad.Mig. y Ma.Piat. desean cambiar de editor, se modifica en los 2


lugares. A priori no podemos saber cuántos autores tiene un libro. Los errores son frecuentes al olvidar
la modificación de un autor. Se pretende modificar en un sólo sitio.

Anomalías de inserción: Se desea dar de alta un autor sin libros, en un principio. NOMBRE y COD_LIB
son campos clave, una clave no puede tomar valores nulos.

Teoría de la normalización:

La teoría de la normalización ofrece una serie de reglas para efectuar una modelización óptima.

La tabla anterior debería dividirse en 3 tablas:

AUTORES (NOMBRE, NACION)


LIBROS (COD_LIB, TITULO, EDITOR)
ESCRIBE (NOMBRE, COD_LIB)

En los años 70 Codd creó las bases de la teoría de la normalización. A cada regla de la teoría la
denominó forma normal. Codd creó las formas normales 1ª, 2ª y 3ª. La 3ª forma normal originó
problemas. Boyce ayudo a solventarlos con la f.n. de Boyce-Codd (FNBC). A finales de los 70 Fagin
creó las formas normales 4ª y 5ª.

Las formas normales se basan en el concepto de dependencia, que comprende las restricciones
definidas sobre los atributos de una relación. Existen diferentes tipos de dependencia:

- Dependencias funcionales (Formas normales 1ª, 2ª y 3ª y FNBC)


- Dependencias multivaluadas (4ª forma normal)
- Dependencia de JOIN (5ª forma normal)

Formas normales

1ª forma normal: es una restricción inherente del modelo relacional. Se decie que una tabla está en 1ª
forma normal si no existen en ella grupos repetitivos.

Una tabla no puede tener en un campo más de un valor.

TITULO AUTOR
CyD Ad.Mig.
Ma.Piat.

Hay un grupo repetitivo. De este modo la tabla no es plana y no está en 1ª forma normal. Para
convertirla a 1ª forma normal:

TITULO AUTOR
CyD Ad.Mig.
CyD Ma.Piat.

2ª forma normal: partimos de la idea de dependencia funcional: Un atributo o conjunto de atributos B


depende funcionalmente de A sí y sólo si a cada valor de A le corresponde un único valor de B:

A  B <=> a cada valor de A le corresponde un único valor de B

A B
x1 y1
x2 y2
x3 y3

Ej: DNI depende funcionalmente de NOMBRE y NOMBRE de DNI

DNI  NOMBRE
NOMBRE  DNI

NOMBRE  DNI

Ej: DIRECCION depende funcionalmente de DNI, pero DNI no depende funcionalmente de DIRECCION

DNI  DIRECCION

DIRECCION ─/ DNI

Ej: TITULO, LIBRO no dependen funcionalmente de DNI, AUTOR, porque un autor puede escribir
varios libros

DNI, AUTOR ─/ TITULO, LIBRO

Ej: Se tiene una base de datos de pluriempleados:

Atributos: DNI, EMPRESA, SUELDO

DNI ─/ EMPRESA


DNI ─/ SUELDO

Se puede concatenar atributos, obteniendo:

DNI, EMPRESA  SUELDO

Sueldo es el atributo implicado que depende de DNI y EMPRESA juntos, que son atributos
implicantes. También:

DNI  NOMBRE, DIRECCION

Las 3 primeras formas normales más la forma normal de Boyce-Codd se basan en dependencias
funcionales obedenciendo al siguiente teorema:
Dada una relación R con un conjunto de atributos A que cumple R(A), xy, es posible una
descomposición en dos tablas de la siguiente manera:

R(A), xy

R(x,y) es una relación compuesta por los atributos que forman la dependencia funcional
R(A-y) es una relación compuesta por los atributos de R excluyendo el atributo implicado

R(A)=R(x, y) R(A-y) el JOIN de ambas forma la relación original.

Las relaciones a partir de ahora se definirán como un conjunto de atributos con dependencias
funcionales R(A, DF).

Para normalizar la tabla habrá que conocer todas las dependencias funcionales, pero en la relación que
nos den sólo tendremos algunas, a partir de las cuales podremos hallar el resto.

Aplicaremos las propiedades de las dependencias funcionales para obtener todo el conjunto de posibles
dependencias funcionales que puedan existir en la relación.

Al conjunto inicial de depndencias funcionales lo llamaremos F, conjunto a partir del cual obtendremos
el resto de depndencias funcionales. A cada nueva dependencia funcional obtenida a partir de F la
llamaré f. Al nuevo conjunto que contenga todas las dependencias funcionales que obtenga el llamaré
F+. Una vez hallado F+ podré aplicar las formas normales de la teoría de la normalización.

Dependencia funcional derivada

Dado un conjunto F de dependencias funcionales se dice que f deriva de F (F ├ f) si f se obtiene a partir


de F.

Cierre de un conjunto de dependencias funcionales

Se define Cierre (F+) como el conjunto de todas las dependencias funcionales implicadas por F o
halladas a partir de F.

Propiedades de las dependencias funcionales

a) Axiomas
b) Propiedades propiamente dichas

a) Axiomas

a.1) Axioma reflexivo

Si Y está incluido en X entonces X  Y (Si Y c X => X  Y)

Ej: CODPROV c CODPOSTAL

CODPOSTAL  CODPROV

A un código postal le corresponde un único código de provincia.

a.2) Aumentatividad

Si X  Y y Z c W => XW  YZ

Se demuestra del siguiente modo: Z c W equivale a W  Z. Si tenemos X  Y y W  Z


podemos afirmar que XW  YZ
a.3) Transitividad

Si X  Y y Y  Z => X  Z
b) Propiedades propiamente dichas

b.1) Unión

X  Y y X  Z => X  YZ

Demostración:

Si X  Y (aumentatividad con X) => X  XY


Si X  Z (aumentatividad con Y) => XY  XZ
Si X  XY y XY  YZ (transitividad) => X  YZ

b.2) Pseudotransitividad

X  Y y WY  Z => WX  Z

Demostración:

Si X  Y (aumentatividad con W) => WX  WY


Si WX  WY y WY  Z (transitividad) => WX  Z

b.3) Descomposición

X  Y y Z c Y => X  Z

Demostración:

Si Z c Y (axioma reflexivo) => Y  Z


Si X  Y y Y  Z (transitividad) => X  Z

Dependencia funcional total

El conjunto de atributos Y tiene dependencia funcional total con X si Y tiene dependencia funcional con
X (X  Y) y además no existe ningún subconjunto Z de X (Z c X) con el cual Y tenga dependencia
funcional (Z ─/ Y).

Diagramas de dependencias funcionales

Son una herramienta que sirve para tener una visión general de los datos y de las dependencias
funcionales entre ellos. S e representa en forma de grafo con los implicantes de las dependencias
funcionales en un rectángulo, de los que salen flechas hacia los implicados.

Ej: Dado: ABC  MNS


MN
BC  OPR
OP
CQ , obtener el diagrama de dependencias funcionales.

A C AB  C

B BC
es una dependencia funcional total.

Ej: Hallar si las siguientes dependencias funcionales son totales:

a) DNI, EMPRESA  SUELDO

b) DNI, EMPRESA  NOMBRE

SUPERCLAVE Y CLAVE

Superclave (SK): es el atributo o conjunto de atributos tales que en una relación R(A, DF) se cumple
que SK  A. SK es el implicante capaz de implicar a la tabla completa.

Ej: En una tabla compuesta por X, Y, Z y W, si W es superclave se cumple que:

WX
WY
WZ

Clave (K): es el atributo o conjunto de atributos tales que en una relación R(A, DF) es superclave y
además no existe ningún subconjunto K' c K tal que K'  A

K, R(A, DF), K ═ SK /\ no existe K' c K / K'  A

Debe tener una dependencia funcional total con los atributos de la tabla. Si tenemos:

WZ  A
WZ  B
WZ  C

pero

Z ─/ A
Z ─/ B
Z ─/ C

la clave es la mínima superclave, no descomponible en claves menores.

2ª forma normal: se dice que una relación está en 2ª forma normal si cumple las siguientes
condiciones:

1) Está en 1ª forma normal


2) Cada atributo no principal o secundario (no forma parte de la clave), tiene una dependencia
funcional total con la clave.

Ej: AB  C
BD

A C

B D

D depende funcionalmente de B sólo y debería depender de AB para estar en 2ª forma normal. Para
convertirlo en 2ª forma normal se descompone en 2 tablas:

Tabla 1: clave con dependencias totales


Tabla 2: parte de la clave implicante con dependencias parciales

A
C B D
B

Esto cumple el teorema 1º enunciado en el capítulo (Descomposición por JOIN)

Ej: Pasar a 2ª forma normal la siguiente tabla:

DNI NOMBRE

EMPLEADO SUELDO

DNI
SUELDO DNI NOMBRE
EMPLEADO

Dependencia funcional transitiva: se cumple si:

A  B
B ─/ A => AC
B  C

Gráficamente:

3ª forma normal: se dice que una tabla está en 3ª forma normal si está en 2ª forma normal y además
cumple que ningún atributo no principal depende transitivamente de la clave.

Ej: Pasar a 3ª forma normal:

A B B  A CD
A C B  C CE
A D B  D
A E B  E

A y B son claves candidatas a principales. Elegimos una de las 2, por ejemplo A.

B
A C
D
E

B
A D
C
E

no está en 3ª forma normal porque existen atributos no principales que dependen transitivamente de la
clave de la relación.

Para pasarlo a 3ª forma normal lo descompongo en 2 tablas:

1ª tabla: clave con dependencias no transitivas.

B
A
C

2ª tabla: clave con dependencias transitivas.

D
C
E

Ej: Tenemos las siguientes dependencias de la tabla ALUMNOS:

NºMATRICULA  AULA, GRUPO


GRUPO  AULA

Pasarlo a 3ª forma normal.

Descomponemos en 2 tablas:

1ª tabla: clave con dependencias no transitivas.

B
A
C

2ª tabla: dependencias transitivas.

D
C
E

Ej: Pasar a 3ª forma normal las siguientes dependencias de la tabla alumnos:

NºMATRICULA  AULA, GRUPO


GRUPO  AULA

Forma normal de Boyce-Codd: Trata de resolver los problemas que origina la 3ª forma normal. Se dice
que una relación R está en FNBC sí y sólo si todo determinante o todo implicante (conjunto de atributos
a la izquierda de la relación) es clave.

Ej:

A
C
B

Está en 3ª forma normal, pero no en FNBC.

AB  C
CB
AB  B

Para pasar a FNBC una relación R en la cual existe una dependencia del tipo X  Y siendo X un atributo
no principal y siendo Y un atributo principal, descomponemos R en 2 proyecciones:

R1 formada por los atributos X e Y  R1=(X, Y)


R2 formada por todos los atributos de R exceptuando Y  R2=(A - Y)

Obtenemos:
C B

Ej: Tenemos una tabla de un callejero:

CALLEJERO (DIRECCION, CIUDAD, C_POSTAL)

C_POSTAL  CIUDAD
DIRECCION, CIUDAD  C_POSTAL

C_POSTAL CIUDAD
DIRECCION
C_POSTAL
CIUDAD DIRECCION

C_POSTAL

Dependencia multivaluada:

Sean A y B dos dubconjuntos distintos de atributos de una tabla T se dice que A tiene una dependencia
multivaluada con B ó que A multidetermina a B ó que B depende multivaluadamente de A (A  B) ai
para cada valor de A tenemos un conjunto, bien sea de valores de B que son independientes de los
demás atributos, o la relación.

1. A <= B
2. Independientemente del resto de atributos de A

Ej:
Los profesores de una facultad mparten varias asignaturas y una asignatura es impartida por
varios profesores.
Una asignatura tiene varios textos y un texto puede utilizarse en varias asignaturas,
independientemente del profesor que las imparte.

PROFESOR ASIGNATURA TEXTO

ANA DIGITALES T1

ANA DIGITALES T2

LUIS DIGITALES T1

LUIS DIGITALES T2

LUIS COMUNICACIONES T2

LUIS COMUNICACIONES T3

Asignatura  Profesor

a) Cada asignatura tiene definidos varios profesores


b) Se cumple

Asignatura  Texto

a) Cada asignatura tiene asignado más de un texto


b) Se cumple

Siempre que se dé una dependencia X  Y tiene que darse una dependencia X  A - (X U Y).
Para que se dé debe tener más de 2 atributos.

Profesor / Texto

a) Para cada profesor hay definidos más de un texto


b) Depende de Asignatura

Profesor  Asignatura

a) Un profesor tiene asignadas varias asignaturas


b) No se puede dar por una serie de teoremas matemáticos

4ª Forma Normal: Una tabla está en 4ªFN si está en 3ªFN y se cumple que las únicas dependencias
multivaluadas existentes son las existentes con los atributos secundarios.
Cuando no existen dependencias multivaluadas y la tabla está en 3ªFN para pasar a 4ªFN tendremos en
cuenta el teorema de FAGIN: "Una tabla T con los atributos A, B, C se puede descomponer sin pérdida
de información en 2 proyecciones: T1 con los atributos A y B y T2 con los atributos A y C, sólo si A
multidetermina a B y C (A  B / C).
Para pasar a 4ªFN si existe una dependencia multivaluada X  Y la dividimos en 2 tablas.

1. R1 (x, y)
2. R2 (A - y)

R1 (x, y)
R: x  y
R2 (A - y)

Ej:

Asignatura  Texto
Asignatura  Profesor

(asignatura,texto) (asignatura, profesor)

R (Asignatura, Texto, Profesor)

1. Asignatura  Texto, x
2. Asignatura  Profesor, y

R1 (Asignatura, Texto, x)
R2 (Asignatura, Profesor, y)

Dependencia de JOIN

Se dice que una relación T formada por los atributos A1, A2, ..., An tiene una dependencia con sus
proyecciones T1, T2, ..., Tn si T=T1 T2 T3 ... Tn

T A B C T1 A B T2 B C

a1 b1 c1 a1 b1 b1 c1
a2 b1 c1 a2 b1 b2 c1

a1 b2 c1 a1 b2 b1 c2

a1 b1 c2

T<> T1 T2

T1 T2 A B C

a1 b1 c1

a1 b1 c2

a2 b1 c1

a2 b1 c2

a1 b2 c1

La 4ª fila (a2, b1, c2) es una tupla intrusa o espúrea.


Hay otra proyección que hace que se cumpla:

T3 A C

a1 c1

a2 c1

a1 c2

T=T1 T2 T3

5ª Forma Normal: Se dice que una tabla está en 5ªFN si está en 4ªFN y además toda dependencia de
JOIN está implicada por las claves de la tabla. Las columnas de enlace deben ser los atributos que
componen la clave.

En la siguiente tabla no existen dependencias funcionales. Bebida ─/ Camarero.

T Clientes Bebidas Camarero

Lopez Cerveza Juan

Lopez Fanta Luis

Garcia Fanta Juan

Perez Cerveza Juan

Dependencias de JOIN:

T=T1 T2 T3

Columna enlace: T1 T2 = Cliente


Los tres atributos forman la clave. T no está en 5ª forma normal. Si las columnas de enlace son las
columnas de la clave entonces está en 5ª forma normal. Para pasarlo a 5ª forma normal habrá que
descomponer T en sus proyecciones.

EMPLEADOS (DNI, NOMBRE, DIRECCION, NSS, FISS, CATEGORIA)

T1 (DNI, NOMBRE, DIRECCION)


T2 (DNI, NSS, FISS)
T3 (DNI, CATEGORIA)

EMPLEADO = T1 t2 t3

T está en 5ª forma normal, aún así es factible descomponerla en sus proyecciones.

Ej: Competiciones

En una prueba hay varios árbitros.


Un árbitro puede arbitrar en diferentes pruebas.
Un atleta puede competir en diferentes pruebas.
En un único país no pueden existir nº de pasaportes iguales, pero sí si son de países diferentes.
Pueden existir distintos atletas con el mismo nombre.

Atributos:

NPa: Nº de pasaporte del atleta


Na: Nombre del atleta
da: Dirección del atleta
dpa: Dirección postal del atleta
ca: Ciudad del atleta
Pra: Provincia del atleta
Pa: País del atleta
cpa: Código de país del atleta
Fn: Fecha de nacimiento del atleta
Sa: Sexo del atleta
cp: Código de la prueba
np: Nombre de la prueba
ma: Marca del atleta
NPar: Nº de pasaporte del árbitro
Nar: Nombre del árbitro

Ej: Barco de pasajeros

Un barco pertenece a un propietario.


Se construye en un sólo astillero.
El código es único dentro del país.
Pueden existir barcos diferentes con el mismo código si son de distintos países.
Un barco es de un sólo tipo.
Los marineros del barco sólo tienen una dirección y un código dentro del barco.
Un marinero puede tener varios teléfonos.
No existen ciudades repetidas.
Dos pasajeros pueden tener el mismo camarote en un barco.
Un pasajero puede embarcar en varios barcos en distintas fechas.
Dos barcos pueden haber tenido a un mismo marinero, pero nunca al mismo tiempo.
Ej: Coleccionistas de sellos

El código de sello particular es único para la colección del propietario.


El código internacional es único para cada tipo de sello emitido, del cual pueden existir varios
ejemplares.
Dos coleccionistas pueden tener ejemplares de un mismo tipo de sello, pero cada uno tendrá un
código particular del sello que podría ser el mismo.
No existen 2 DNIs, ciudades, provincias o países iguales.
Pueden existir nombres iguales.
Un propietario pude tener varios teléfonos.

Atributos:

CS: Código particular del sello para el propietario actual


CI: Código internacional del sello
PS: Pais del sello
CP: Código del país
VE: Valor de emisón del sello
AE: Año de emisión del sello
EP: Estado político del país en el año de emisión del sello
CE: Código del estado político
CLS: Clase de sello
CCL: Código de la clase de sello
EC: Estado de conservación del sello
CC: Código del estado de conservación del sello
DNIP: DNI del propietario del sello
NP: Nombre del propietario del sello
DP: Dirección del propietario del sello
CiP: Ciudad del propietario del sello
CPP: Código postal del propietario del sello
PP: Provincia del propietario del sello
PaP: País del propietario del sello
TP: Teléfono del propietario del sello
DNIA: DNI del antiguo propietario del sello

SQL Embedido

1. SQL autocontenido
2. SQL embedido

SQL embedido:

Sentencia de SQL que se utiliza dentro de un programa llamado anfitrión, escrito en cualquier lenguaje.
Tendremos tablas con datos de entrada y de salida.
Las sentencias de SQL serán sentencias embedidas en el programa anfitrión.

Características:

* Todas las sentencias SQL van a estar enmarcadas por:

EXEC SQL
<sentencias>
END-EXEC

* Antes de utilizar un compilador para manejar SQL embedido es necesario pasar el programa fuente por
un precompilador:

PROG precompilador PROG FUENTE compilador PROG LINKER


FUENTE MODIFICADO OBJETO

├ sintaxis sentencias SQL
├ comentar sentencias SQL (para que las ignore el compilador)
└ sustituir sentencias SQL por llamadas a rutinas de librerías

* Manejo de variables de programa dentro de sentencias SQL:

Se pone dos puntos (:) delante del nombre de la variable.

Ej: Para un vuelo, visualizar plazas libres y nº de vuelo (datos de salida), sabiendo el origen,
destino, hora de salida y fecha de salida (datos de entrada).

INICIO
escribir 'Introducir ORIGEN, DESTINO, FECHA, HORA'
leer ORIGEN, DESTINO, FECHA, HORA
EXEC SQL
SELECT RESERVAS.NUM_VUELO, PLAZAS_LIBRES
INTO :VUELO, :PLAZAS
FROM RESERVAS, VUELOS
WHERE RESERVAS.NUM_VUELO=VUELOS.NUM_VUELO
AND ORIGEN=:ORIGEN
AND DESTINO=:DESTINO
AND FECHA=:FECHA
AND HORA=:HORA
END-EXEC
escribir VUELO, PLAZAS
FIN

INTO sirve para determinar las variables de salida.


Devuelve en la salida 1 sóla fila. En caso de que la salida devuelva más de una fila tendremos los
cursores.

Cursor:

Es una estructura de datos tabular (en forma de tabla) que sirve para almacenar un número
indeterminado de filas.
Sólo permite manejar una única fila a la vez, mediante un puntero.
Para manejar cursores en SQL embedido hay 4 etapas:

1) Definición del cursor

Se define junto a la declaración de variables del programa anfitrión:


EXEC SQL
DECLARE
<nom_cursor> CURSOR
FOR
<sent_select>
END-EXEC

2) Abrir cursor

Rellena de filas la estructura del cursor:

EXEC SQL
OPEN <nom_cursor>
END-EXEC

3) Recuperar filas (1)

EXEC SQL
FETCH <nom_cursor> {avanza el puntero una posición}
INTO <lista_variables> {una sóla variable por columna}
END-EXEC

Cuando se hace un OPEN se rellena la estructura y el puntero se posiciona anterior a la primera fila. El
primer FETCH posiciona el cursor en la primera fila.

4) Cerrar cursor

EXEC SQL
CLOSE <nom_cursor> {liberando memoria}
END-EXEC

Ej: Realizar un programa que presente todos aquellos vuelos existentes entre un origen y un
destino determinados.

Pasos:

1. Declaración de variables
2. Petición de información de origen y destino
3. Abrir cursor
4. Recuperar primera fila del cursor
5. Comprobar si existe alguna fila. Si no existe ir a 9
6. Escribir fila en pantalla
7. Recuperar siguiente fila
8. Ir a 5
9. Fin

VARIABLES
ORIGEN, DESTINO, HORA, VUELO: STRING

EXEC SQL
DECLARE lista_vuelos CURSOR
FOR SELECT NUM_VUELO, HORA_SALIDA
FROM VUELOS
WHERE ORIGEN=:ORIGEN
AND DESTINO=:DESTINO
END-EXEC
INICIO
ESCRIBIR 'INTRODUZCA ORIGEN Y DESTINO'
LEER ORIGEN, DESTINO
EXEC SQL
OPEN lista_vuelos
END-EXEC
EXEC SQL
FETCH lista_vuelos
INTO :VUELO, :HORA
END-EXEC

{Variable predefinida SQL-CODE: nos da información sobre la ejecución de cada sentencia en SQL:
SQL-CODE < 0  Error
SQL-CODE = 100  CURSOR vacío
SQL-CODE > 0  Warning}

MIENTRAS SQL-CODE <> 100


ESCRIBIR VUELO, HORA
EXEC SQL
FETCH lista_vuelos
INTO :VUELO, :HORA
END-EXEC
FIN_MIENTRAS
EXEC SQL
CLOSE lista_vuelos
END-EXEC
FIN

INTEGRIDAD E INTEGRIDAD REFERENCIAL

1. Introducción
2. Integridad referencial
2.1 DDL
2.2 DML
3. Disparadores
4. Reglas semánticas

1. INTRODUCCION

Integridad: característica que nos permite tener coherencia y veracidad en la información.


Existen ciertas operaciones de SQL que pueden hacer peligrar la integridad de la operación:

- Inserción
- Borrado
- Modificación

T.PADRE EMPLEADO DNI Clave Principal

depende
cod_fam
T.HIJA FAMILIARES DNI_EMP Clave Ajena

Puede que borremos un empleado y olvidemos eliminar los familiares.

Tipos de integridad:

Integridad de dominio: restringimos los valores que puede tomar un atributo respecto a su dominio, por
ejemplo EDAD  18 - 65.
Integridad de entidad: la clave primaria de una entidad no puede tener valores nulos y siempre deberá
ser única, por ejemplo DNI.
Integridad referencial: las claves ajenas de una tabla hija se tienen que corresponder con la clave
primaria de la tabla padre con la que se relaciona. Por ejemplo, en familiares necesitaremos el DNI de
empleado, que es la clave ajena de la tabla.

2. INTEGRIDAD REFERENCIAL

Clave principal: conjunto de atributos capaz de diferenciar cada tupla de la tabla.


Clave ajena: Clave en la tabla padre.

2.1 DDL

Se basa en la definición de la clave principal y de la clave ajena de la tabla.

CREATE TABLE EMPLEADO


(PRIMARY KEY DNI,
DNI CHAR(8) NOT NULL,
NOMBRE VARCHAR(30) NOT NULL, {columnas de la tabla, clave incluida}
. . .
)

CREATE TABLE FAMILIARES


(PRIMARY KEY COD_FAMILIAR,
COD_FAMILIAR CHAR(4) NOT NULL,
NOM_FAMILIAR CHAR(30) NOT NULL,
DNI_EMPL CHAR(8) NOT NULL,
. . .
)
FOREIGN KEY REL_EMPL_FAM
DNI_EMPL REFERENCE EMPLEADO
RESTRICT
ON DELETE CASCADE
SET NULL

2.2 DML

Tendremos una serie de reglas para:

2.2.1 Inserción
2.2.2 Actualización
Implícitas o determinadas por el sistema.

2.2.3 Borrado

Explícita o definida por el usuario de tres que proporciona el sistema.

2.2.1 Regla de inserción

Se ejecuta sobre la tabla hija.


Sólo se podrá insertar una fila en la tabla hija si el valor de clave ajena de esa fila es un valor nulo o un
valor de los existentes en la clave primaria de la tabla padre.

2.2.2 Regla de actualización

Se ejecuta sobre las tablas padre o hija.

Tabla padre: no se puede modificar el valor de clave primaria de la tabla padre si existe alguna fila en
la tabla hija que lo referencie en la clave ajena.

Tabla hija: el valor de clave ajena de la tabla hija sólo se puede modificar si el nuevo valor que va a
adoptar es un valor nulo o es igual a un valor de clave primaria de la tabla padre.

2.2.3 Regla de borrado

Esta regla se especifica al crear la tabla padre y se activará cuando se intente eliminar una fila de la
tabla.

CREATE TABLE
...
FOREIGN KEY
...
RESTRICT

ON DELETE CASCADE

SET NULL

Es una regla explícita, ya que el usuario puede elegir la regla de borrado que desee, a partir de 3 reglas
que nos va a proporcionar el sistema.

a) RESTRICT

No se puede borrar una fila de la tabla padre si existen filas en la tabla hija cuyos valores de
clave ajena sean iguales a valores de clave primaria de la fila que queremos borrar.

b) CASCADE

Cada vez que se borre una fila de la tabla padre se eliminarán aquellas filas de la tabla hija que
tengan como valor de clave ajena el mismo valor que el de la clave primaria de la fila que se quiere
borrar.

c) SET NULL

Cada vez que se elimine una fila de la tabla padre se actualizarán los campos de la clave ajena
de la tabla hija a valores nulos para aquellas filas que tengan en el campo de la clave ajena el mismo
valor que la clave primaria de la fila de la tabla padre que se quiere borrar.

Casos específicos de integridad:

Integridad auto-referencial

Una tabla es al mismo tiempo padre e hija de si misma.

Ej: Dada la tabla T_EMP con las siguientes columnas:

COD_EMP NOMBRE COD_EMP_JEFE

Todos los valores que aparezcan en la última columna existirán también en la primera, por tanto
COD_EMP_JEFE se convierte en clave ajena de la tabla.

Ciclos de integridad referencial

Conjunto de tablas que funcionará como tablas padres e hijas unas de otras, formando un camino
cerrado.

Ej: Tenemos 3 tablas:

COCHES (MATRICULA, MARCA, COD_DIRECTOR)

DIRECTORES (COD_DIRECTOR, NOMBRE_DIR, COD_SECRETARIA)

SECRETARIAS(COD_SECRETARIA, NOMBRE_SEC, MATRICULA)

COCHES es tabla hija de DIRECTORES


DIRECTORES es tabla hija de SECRETARIAS
SECRETARIAS es tabla hija de COCHES

COCHES

DIRECTORES SECRETARIAS

Forma un ciclo de integridad referencial.

Por haber ciclos debemos incorporar restricciones de borrado, para un correcto funcionamiento de la
integridad referencial.

Restricciones de borrado

a) Integridad auto-referencial

Siempre que tengamos una tabla con integridad auto-referencial debemos definir un borrado en
cascada.

Tabla EMPLEADO

COD_EMP COD_EMP_JEFE

A00 -
B01 A00

C02 B01

D03 C02

DELETE FROM EMPLEADO


WHERE COD_EMP_JEFE >= 'B01'

Con RESTRICT no se puede borrar la 3ª fila, porque C02, clave primaria, está siendo referenciada en la
fila 4ª como clave ajena. Salta a la 4 fila y la borra.

DELETE FROM EMPLEADO


WHERE COD_EMP_JEFE IS NULL

Con SET NULL borraría la primera fila, porque su clave ajena es NULL, pasaría a la 2ª y como su clave
ajena es igual a la clave primaria de la fila borrada pondría la clave ajena a NULL. Como le hemos dicho
que borre aquellas filas que tengan por clave ajena un valor nulo, ahora borraría esta fila y así
sucesivamente hasta eliminar la tabla completa.

b) Ciclos de integridad referencial

DELETE FROM T3
WHERE FKT2 IS NULL

Restricciones de borrado en ciclos:

CICLO DE 2 TABLAS: ninguna de ellas podrá tener definida la opción de borrado en cascada.
CICLO DE MAS DE 2 TABLAS: Sólo una de las tablas podrá tener la opción de borrado en cascada.

El esquema anterior no cumple las restricciones expuestas.


c) Tablas conectadas por múltiples caminos (con más de una tabla padre)
DELETE FROM T2
WHERE PKT2 = 'T2A'

Restricciones de borrado en tablas conectadas por múltiples caminos:

Los dos caminos que llegan a una tablas deben tener definida siempre la misma regla de borrado, que
debe ser RESTRICT o CASCADE.

En el ejemplo funcionaría bien por el primer camino, pero por el segundo hay restrinción.

Ej. propuesto: Pruébese que ocurriría si entre T3 y T1 hay SET NULL y entre T2 y T1 hay SET NULL.

Ventajas del uso de las reglas de integridad referencial proporcionadas por el sistema frente a la
implementación de estas por parte del usuario.

1. Al usar las proporcionadas por el sistema los analistas tienen menor responsabilidad.

2. Habrá un incremento en la productividad y un decremento en los costes de la aplicación, porque el


número de pruebas a realizar será menor si la integridad referencial es implementada por el propio
sistema, el cual nos garantizará el correcto funcionamiento de las reglas de integridad referencial. El
tiempo de desarrollo de la aplicación será menor.

3. La información será más coherente, ya que está garantizado que todas las filas de las tablas cumplen
las normas de integridad referencial.

3. DISPARADORES O 'TRIGGERS'

Son un conjunto de sentencias que el sistema ejecuta a la hoara de efectuar una inserción,
actualización o borrado en una tabla. Para definir un TRIGGER necesitamos:

- Nombre de la tabla sobre la que actuará el trigger


- Sentencia que activará el trigger (inserción, actualización o borrado)
- Acciones que realizará el trigger

DB2 no incorpora la posibilidad de definir triggers, pero SQL sí. Las reglas de integridad
referencial se emulan en SQL mediante la implementación de triggers.

Emulación de inserción en tabla hija mediante el uso de trigger en SQL:

Según la regla deintegridad referencial, no se puede efectuar una inserción en una tabla hija a menos
que exista un valor de clave primaria igual al de clave ajena de la fila que se desea insertar.

Definición del trigger:

DEFINE TRIGGER insercion


ON INSERT OF HIJA

El trigger comparará el valor de clave ajena de la fila a insertar con el valor de clave primaria de la
tabla hija cada vez que se intente insertar una fila.

Implementación del trigger:

(if (SELECT COUNT (#)


FROM PADRE, INSERTED
WHERE PADRE.CL_PRIMARIA = INSERTED.CL_AJENA) = 0) Condición que activa el trigger
begin
PRINT 'ERROR'
ROLLBACK TRANSACTION Acciones que ejecuta el trigger si se activa
end

SELECT COUNT devuelve el número de filas de la tabla padre con un valor de clave primaria igual a la
clave ajena de la fila a insertar.
El sistema proporciona una tabla de almacenamiento temporal (INSERTED) donde se guardarán las filas
a insertar.
Si CL_AJENA = CL_PRIMARIA, permite la inserción, en caso contrario deshace la operación con
ROLLBACK TRANSACTION.

El trigger correspondiente a la operación de actualización sería similar.

También podría gustarte