Tema 2
Tema 2
Ingeniería
Informática
BASES DE DATOS
TEMA 2
Primeros pasos con SQL
Docentes:
I. Introducción
En este tema veremos como expresar en lenguaje SQL los conceptos del modelo relacional vistos en el tema anterior.
Es por tanto un tema práctico que se recomienda que estudies con el ordenador al lado y probando cada ejemplo en el
SGBD PostgreSQL, cuya descarga y PDF con instrucciones de instalación se te facilita en UBUVirtual en los enlaces:
• Guia breve de instalación de PostgreSQL Archivo
• Página de descarga de PostgreSQL
II. Objetivos
OBJETIVO 1: Reforzar los contenidos de bases de datos relacionales vistos en el tema anterior practicando
con ellos en el lenguaje SQL.
OBJETIVO 2: Conocer los tipos de datos SQL que utilizaremos durante el curso.
OBJETIVO 3: Conocer el valor nulo, su utilidad, y anticipar las dificultades que se presentarán en temas
posteriores si no lo interpretamos correctamente.
OBJETIVO 4: Conocer la sintaxis básica del lenguaje SQL que permita crear tablas y vistas, y hacer altas,
bajas y modificaciones simples. La consultas se posponen para más adelante.
OBJETIVO 5: Hacer hincapié sobre la definición de restricciones relacionales mediante SQL.
OBJETIVO 6: Acostumbrar al alumno a la programación de scripts SQL como forma de estudiar y practicar la
mayor parte de lo que queda de asignatura.
IMPORTANTE:
1. En este tema hay comentarios a modo de ampliación; aparecen en gris y no entran como materia del curso,
constan sólo a modo de ampliación.
2. A lo largo del tema, además, se proponen unos pocos ejercicios que no hay que entregar al profesor. Son
para que los hagas por tu cuenta y afiances los contenidos. Esto no quita para que consultes al profesor
aquellos ejercicios que te susciten dudas.
3. Los scripts (ficheros) SQL a los que se hace referencia, típicamente en los ejercicios, están colgados en
UBUVirtual en el enlace Scripts SQL del Tema 3 que se encuentra debajo del enlace correspondiente al
presente PDF.
Bases de Datos 3
Grado en Ingeniería Informática
1. El lenguaje SQL
SQL es el lenguaje estándar de manejo de bases de datos que se utiliza en la industria. Hay varias versiones de este
estándar pues se ha ido ampliando con el tiempo, la que vamos a ver aquí se corresponde con las características
añadidas en 1992 (SQL-2 o SQL-92) [Melton y Simon 1993] que son las más utilizadas.
SQL representa la información mediante tablas, también llamadas relaciones. Por eso se dice que estas bases de datos
son relacionales.
Las tablas tienen un conjunto de campos o atributos representando características de los elementos que modelan las
tablas. Por ejemplo, una tabla de oficinas puede tener un campo código, otro ciudad y otro objetivo de ventas. Cada
fila de la tabla representa un elemento de la misma, en este caso una oficina.
El lenguaje SQL se dice que es declarativo, en tanto no especificamos cómo obtener los resultados de una petición a
la base de datos, sino qué es el propio sistema el que aplica el algoritmo que considera más adecuado para resolver
cada petición.
2. Ahora lo vamos abrir desde pgAdmin III. Para ello, pulsa el botón en la parte superior, y en la
ventana emergente se te mostrará un editor SQL y con Archivo > Abrir, abre el script anterior.
Bases de Datos 4
Grado en Ingeniería Informática
Eliminaría la tabla examen recién creada, con toda la información que contuviese (los tres alumnos). Observa que
acaba en punto y coma. Todos los comandos SQL acaban en punto y coma.
DROP TABLE es un comando DDL (del sublenguaje de definición de datos).
Ejercicio 1:
Modifica PR1_01.sql de forma que:
1. Borre la tabla antes de crearla. Hazlo así
Bases de Datos 5
Grado en Ingeniería Informática
Si no pones el IF EXISTS y no existiera también daría error por intentar borrar una tabla inexistente. IF
EXISTS funciona en postgreSQL pero no es estándar ANSI/ISO.
2. Muestre los resultados (SELECT *) después de insertar las 3 filas.
3. Añade comentarios al script.
4. Llámalo PR1-03.sql
Comprueba que ahora los puedes ejecutar tantas veces como quieras.
Como vemos, el comando CREATE TABLE consiste en especificar dichas palabras seguidas del nombre de la tabla
que queremos crear (en este caso Oficinas). A continuación, entre paréntesis viene una lista de especificaciones de
campo. Las especificaciones de campo se separan entre si mediante comas. Al final del todo, aparece el terminador de
sentencia SQL, que es el punto y coma.
Toda sentencia SQL termina en punto y coma. El SQL no distingue entre mayúsculas y minúsculas, por lo que la
siguiente declaración, es equivalente a la anterior:
Con lo que ya sabemos podemos deducir bastantes cosas de esta declaración. Por ejemplo: que la tabla oficina tiene
tres campos, el primero es cod y parece un código numérico (un entero) que es clave primaria. El segundo campo se
Bases de Datos 6
Grado en Ingeniería Informática
llama ciudad y parece una cadena de caracteres de longitud máxima quince. El último campo es objetivo, podemos
adivinar que es numérico, ya veremos más tarde que significan todos los modificadores DEFAULT y NOT NULL que
aporta la declaración de este campo objetivo.
Para SQL da lo mismo un tabulador, que un retorno de carro, que un espacio en blanco, por lo que el hecho de que la
declaración anterior aparezca en cinco líneas es meramente casual, y en todo caso responde a un criterio de claridad,
pues podría haberse declarado perfectamente de la siguiente manera:
Igualmente con DROP TABLE podíamos haber loncheado la declaración en varias líneas, y podíamos haber utilizado
mayúsculas y minúsculas indistintamente.
Bases de Datos 7
Grado en Ingeniería Informática
1 Para ser rigurosos en realidad son números racionales, pero en un abuso del lenguaje la gente habla de reales.
Bases de Datos 8
Grado en Ingeniería Informática
Bases de Datos 9
Grado en Ingeniería Informática
Según el estándar los literales fecha hora serían por ejemplo así:
• Para especificar el literal DATE correspondiente al día 8 de abril de 2005 en formato europeo:
DATE '08-04-2005'
TIME '20:30'
• Para especificar el literal TIMESTAMP correspondiente al día 8 de abril de 2005 a las 8 y media
de la tarde haríamos:
Bases de Datos 10
Grado en Ingeniería Informática
Bases de Datos 11
Grado en Ingeniería Informática
Para especificar una cláusula DEFAULT, se pone DEFAULT seguido de un literal del mismo tipo que el
campo en cuestión. Por ejemplo, también son válidos:
Otra posibilidad, es que en lugar de un literal invoquemos a una variable del sistema. El caso más habitual
es utilizar en un campo DATE, TIME o TIMESTAMP la fecha del sistema:
CURRENT_DATE es una variable estándar que devuelve un DATE con la fecha del sistema, y
CURRENT_TIMESTAMP es otra variable estándar que devuelve un TIMESTAMP con la fecha-hora del
sistema.
4. Finalmente, de manera opcional también, podemos declarar una lista de restricciones de columna. Por
ejemplo podemos decir que la columna IdAlumno tiene la restricción de ser clave primaria, y que además
ha de ser mayor que cero, lo cual son dos restricciones que se formularían así:
Más adelante veremos cómo especificar todas las restricciones que puede llevar un campo. De momento
debemos quedarnos con la idea de que pueden ser varias, una o ninguna, y que cuando son varias se pueden
declarar en cualquier orden, por ejemplo la anterior especificación de campo es equivalente a esta otra:
Se puede combinar una cláusula DEFAULT con una lista de restricciones de columna, siempre que
respetemos el orden, es decir el DEFAULT tiene que ir antes de las restricciones de columna. Por ejemplo:
serviría para especificar que el saldo tiene valor por defecto cero, nunca puede estar vacío (not null) y ha de
tener un valor mayor o igual que cero.
Bases de Datos 12
Grado en Ingeniería Informática
mismo, no puede quedarse sin valor. Es importante notar que esto no impide que un campo numérico no
tome el valor cero, pues el cero es un valor, y es por tanto, distinto del nulo. De la misma forma, esta
restricción no impide que una columna de tipo cadena tome como valor la cadena de longitud cero (la
cadena vacía o ''), pues '' es una cadena válida y es distinta que nulo, o que un campo booleano valga falso.
• PRIMARY KEY: Sirve para decir que esa columna es la clave primaria de la tabla (por tanto, PRIMARY
KEY como restricción de columna sólo permite especificar claves primarias simples2). En el SQL-92 y
posteriores cuando un campo es declarado como PRIMARY KEY automáticamente asume que es NOT
NULL, por lo que una declaración del tipo PRIMARY KEY NOT NULL, es válida, pero es redundante, en
tanto valdría con poner PRIMARY KEY a secas.
La teoría de las bases de datos relacionales obliga a que toda tabla tenga clave primaria, sin embargo SQL
deja declarar tablas sin PRIMARY KEY. Por norma nosotros no nos tomaremos nunca semejante licencia.
Como ocurría en la teoría del modelo relacional, una tabla SQL no puede tener más de dos declaraciones
PRIMARY KEY.
• UNIQUE: Sirve para decir que esa columna es una clave candidata no-primaria de la tabla. Una clave
candidata no primaria, es una clave que podría haber sido elegida como primaria. Por ejemplo, podemos
identificar al coche por su matrícula o quizás por su número de bastidor. Probablemente decidamos que la
matrícula es clave primaria, pero aún así deseamos que no pueda haber dos coches con el mismo número de
bastidor. La solución es declarar el número de bastidor como UNIQUE.
Como ocurre con las claves primarias, las candidatas también podrían ser compuestas, pero UNIQUE como
restricción de columna sólo permite especificar claves candidatas simples3. A diferencia de PRIMARY
KEY, el sistema no asume que UNIQUE implique NOT NULL, por lo que una declaración del tipo
UNIQUE NOT NULL, es distinta que UNIQUE a secas.
Una tabla SQL puede tener más de una declaración UNIQUE o puede no tener ninguna.
• REFERENCES <tabla referenciada>: Sirve para definir la restricción de integridad referencial asociada a
una clave ajena. Lo veremos en más adelante en la sección 4..
• CHECK: Sirve para especificar una restricción de valor. Es decir, para prohibir determinados valores de un
campo. Para ello, CHECK se hace seguir de un predicado lógico que va especificado entre paréntesis. Por
ejemplo, si quiero que el campo númeroHorasExtras no tome nunca valores negativos haré:
En principio, la complejidad del predicado lógico que especifiquemos en un CHECK puede ser notable, e
iremos viendo algunas posibilidades más adelante, pero en la práctica van a seguir casi siempre el esquema
donde el comparador puede ser uno de estos, equivalentes a los que conoces de la asignatura de
Programación de primero: =, <, >, <=, >=, !=, y además <> que también significa distinto como !=. Observa
que la igualdad es con un solo igual, y que el distinto se puede expresar de dos maneras: estilo Pascal (<>)
o estilo C (!=).
El comparando normalmente es un literal (lógicamente del mismo tipo que el campo), pero nuevamente
podría ser una variable del sistema, como por ejemplo
Bases de Datos 13
Grado en Ingeniería Informática
El comparando podría ser producto de una expresión, típicamente aritmética, por ejemplo:
Es posible complicar las restricciones CHECK con AND OR y paréntesis, por ejemplo
Ejercicio 3:
Modifica PR1-04.sql para que cree 3 tablas con los siguientes campos:
1. Oficinas, tiene un campo cod que es entero y clave primaria y que no sea nunca nulo, otro ciudad que es
una cadena de longitud máximo 15 que por defecto vale BURGOS, y objetivo que es numérico con 5
dígitos enteros y 2 decimales con valor por defecto cero y que no sea nunca nulo.
2. Empleados, que tiene un campo nombre que es una cadena de longitud máximo 20 y que además es clave
primaria; estado que es una letra o carácter; salario que es un número con 4 dígitos enteros y 2 decimales
que debe de tomar siempre un valor mayor que cero pero puede estar vacío, fecha de nacimiento que es de
tipo fecha y nunca debe de estar vacío.
3. Clientes: que tenga como clave primaria un entero codcli, pero que además almacene el NIF del cliente (8
dígitos) el cual no se puede repetir, ni puede estar vacío. También se quiere guardar la Razón Social que
también es única y no vacía en como máximo 25 caracteres, la ciudad en como máximo 13 también es un
campo obligatorio, y por último 9 dígitos para el teléfono que es un campo opcional.
Guarda el resultado en PR1-06.sql.
Bases de Datos 14
Grado en Ingeniería Informática
CONSTRAINT nombre_constraint
NOT NULL
(columna)
UNIQUE
REFERENCES tabla
Como puede verse en la Figura 1, para dar un nombre a una restricción basta poner delante de su declaración la
palabra clave CONSTRAINT seguida del nombre que queremos darla, que no llevará separadores en su interior
(espacios, tabuladores etc...). Por ejemplo:
En este caso hemos dado el nombre “PK_Alumno” a la restricción de clave primaria. Como DEFAULT no es una
restricción nunca puede llevar una clausula CONSTRAINT, pero todas las demás (UNIQUE, PRIMARY KEY,
FOREIGN KEY/REFERENCES, NOT NULL y CHECK) pueden llevar nombre si así lo deseamos. Es recomendable
que las restricciones sean nombradas con un prefijo que nos indique que tipo de restricción es, por ejemplo:
Restricción Prefijo
PRIMARY KEY PK_
FOREIGN KEY REFERENCES FK_
CHECK CHK_
UNIQUE UNQ_
Tabla 1: Ejemplos de prefijos para nombrar las restricciones.
Así, cuando el sistema nos lance un mensaje de error diciendo que se ha intentado violar la restricción PK_Alumno,
sin prácticamente saber nada mas, podemos intuir que es que hemos intentado meter un valor repetido en la clave
primaria de la tabla de alumnos.
Nota que en la tabla no se ha incluido un prefijo para las restricciones NOT NULL. No es que no se pueda dar un
nombre a estas restricciones, es que en una base de datos de un sistema medio podría haber varios cientos o miles de
restricciones NOT NULL, ya que buena parte de los campos podrían ser NOT NUL, y normalmente los
programadores no disponen de tiempo para nombrarlas.
Bases de Datos 15
Grado en Ingeniería Informática
Ejercicio 4:
Abre PR1-06.sql y da nombre a todas las restricciones posibles siguiendo el criterio de la Tabla 1. Guarda el resultado
en PR1-07.sql.
Esta declaración es errónea, pero habitual entre los principiantes. Fíjate que no estás declarando una clave primaria
compuesta, sino dos claves primarias simples, y una relación no puede tener más de una clave primaria, por lo que
dará un error del SGBD.
Entonces, ¿cómo se hace para declarar una clave primaria compuesta?. Lo que se hace es llevar la declaración al final
de la tabla, tal que así:
Este tipo de declaración se conoce como fuera de linea, o de restricción de tabla. Observa que ahora, detrás del último
campo se ha puesto una coma para dejar claro que finaliza la declaración de ese campo y empieza la declaración de
una restricción fuera de línea.
Todas las restricciones se pueden declarar fuera de línea excepto NOT NULL 4. La razón es que no tiene sentido que
NOT NULL abarque a más de un campo simultáneamente, sin embargo PRIMARY KEY, UNIQUE y REFERENCES
pueden ser compuestas, y el CHECK en su predicado puede involucrar a más de un campo.
Podemos tener en una misma tabla varias restricciones fuera de línea, por ejemplo:
Bases de Datos 16
Grado en Ingeniería Informática
Por tanto, tenemos cuatro formas sintácticas posibles de una restricción, que vienen de combinar el caso con
nombre/sin nombre, con el caso en línea/fuera de línea.
A continuación revisaremos una por una todas las restricciones para ver cómo se declaran fuera de línea:
• NOT NULL: No se declara nunca fuera de línea, sería erróneo. Normalmente los diseñadores de base de
datos rara vez le ponen nombre, si bien es posible. Por ejemplo:
• UNIQUE: Es necesario declararla fuera de línea si la clave candidata es compuesta. Sino, podemos elegir
entre declararla en línea o fuera de línea.
Bases de Datos 17
Grado en Ingeniería Informática
La declaración fuera de línea consistirá en la palabra clave UNIQUE seguida por la lista de campos que
componen la clave candidata. Esta lista vendrá entre paréntesis, y cada elemento de la lista vendrá separado
del siguiente por una coma.
Naturalmente, para nombrarla debe de estar precedida por la clausula CONSTRAINT.
Por ejemplo:
Ten cuidado, ya sabes que UNIQUE no implica NOT NULL, si quieres que los campos de la clave
candidata no sean nulos lo tendrás que especificar aparte, como en el ejemplo que hemos hecho con
ciudad5.
• PRIMARY KEY: Es necesario declararla fuera de línea si la clave primaria es compuesta. Sino, podemos
elegir entre declararla en línea o fuera de línea.
La declaración fuera de línea consistirá en la palabra clave PRIMARY KEY seguida por la lista de campos
que componen la clave primaria. Esta lista vendrá entre paréntesis, y cada elemento de la lista vendrá
separado del siguiente por una coma.
Naturalmente, puede nombrarse precediéndola con la clausula CONSTRAINT.
Por ejemplo:
Como PRIMARY KEY implica NOT NULL, los dos campos que componen la clave primaria son en este
caso NOT NULL aunque no lo hubiéramos puesto en ninguno de ellos. Por tanto, el NOT NULL de
FechaMuestra es redundante y podría/debería omitirse.
• CHECK: El caso del CHECK es especial. Para entenderlo necesitamos un CHECK en el que en el
predicado al menos intervengan dos campos. Por ejemplo, supongamos:
5 En ese sentido, por ejemplo con la declaración de arriba el sistema no considera que dos filas con la ciudad igual a 'Burgos' y la
fechaMuestra nula sean dos filas con la clave candidata repetida. La explicación es que si fecha es nula, es entonces
desconocida, y si es desconocida el sistema no puede asegurar que esas dos filas tengan valores repetidos para esa declaración
UNIQUE.
Bases de Datos 18
Grado en Ingeniería Informática
CREATE TABLE A(
Campo1 INTEGER CHECK (Campo1>Campo2),
Campo2 INTEGER CHECK (Campo1>Campo2)
);
Una restricción CHECK en línea nos puede dar problemas dependiendo del SGBD con el que trabajes. A
veces simplemente no deja contener una referencia a un campo distinto del campo en el que se declara la
restricción. Es decir:
podría tratarla como incorrecta porque en el CHECK hay una referencia a Campo2. De la misma forma, el
check en el campo Campo2 sería incorrecto por tener una referencia al Campo1.
Otras veces el efecto puede ser contrario al deseado. Por ejemplo, puede parecer que tener declarados los
dos CHECKs es redundante, y que basta con uno de los dos. Pero hay sistemas que comprobarían el
CHECK sólo cuando cambiase el campo en el que está declarado. Por tanto, si sólo declaras la restricción
en el Campo1 podrías insertar la fila < Campo1=2, Campo2=1> y luego cambiar el Campo2=4, y así
violar la restricción sin que el sistema se quejase.
La forma de declarar una restricción CHECK que afecta a n campos y que funcione en cualquier SGBD, es
declararla como restricción de tabla, tal que así:
CREATE TABLE A(
Campo1 INTEGER,
Campo2 INTEGER,
CHECK (Campo1>Campo2)
);
Por tanto, cuando un CHECK afecta a un solo campo da igual declararlo en línea que fuera de línea, pero si
afecta a más de un campo, en general, lo declararemos como restricción de tabla.
Ejercicio 5:
Crea una taba artículos con los siguientes campos: cod_Seccion, cod_Articulo, cod_Armario y existencias son
cuatro campos enteros, los campos precio y coste son numéricos con tres dígitos enteros y dos decimales. Todos los
campos son obligatorios. Además:
• Las existencias siempre son positivas o cero
• El precio tiene que ser mayor o igual que el coste
• Los valores del código de artículo son únicos para cada fila y se utilizarán como clave primaria.
• La combinación de valores entre el código de sección y el de armario también es única para cada fila, pero
no se utilizará como clave primaria.
Se pide crear un script PR1-08.sql que cree la tabla de artículos declarando todas las restricciones posibles
fuera de línea, y otro PR1-09.sql que declare todas las restricciones que pueda en línea.
Bases de Datos 19
Grado en Ingeniería Informática
Por ejemplo, supongamos una tabla de oficinas con los campos objetivo, ciudad y cod:
La lista de columnas en este caso está formada por tres campos, los cuales vemos que están separados por comas. A
continuación, la cláusula VALUES contiene una lista con el mismo número de valores que columnas se haya
especificado en la lista de columnas (tres en este caso).
La asignación de valores a campo, se hace teniendo en cuenta el orden en el que se han especificado cada uno de los
elementos en las listas. Así el valor del campo objetivo de la nueva fila tomaría el valor 2000000 por ser el primer
valor, ciudad tomaría el valor Valladolid por ser la segunda, y cod tomaría el valor 8 por ser la tercera y última.
Al hacer una inserción no tenemos por qué dar valor a todas las columnas de una tabla, sino sólo a algunas de ellas,
por ejemplo:
Observa comparando con la sentencia INSERT de la oficina de Valladolid, que el orden en el que especificamos las
columnas es irrelevante.
La lista de columnas se puede omitir si se cumplen simultáneamente estas dos condiciones:
1. Damos valores a todos los campos de la tabla.
2. Los valores se dan en el mismo orden en el que han sido declarados los campos en el momento en el que se
hizo CREATE TABLE.
Así, si se hizo:
Vemos que como la tabla tiene tres campos, el INSERT tiene que proveer tres valores y además el primero se supone
que es el objetivo, pues es el primero que se declaró en el CREATE TABLE, el segundo de supone que es la ciudad,
pues la ciudad es el segundo campo declarado en el CREATE TABLE, etc.
Bases de Datos 20
Grado en Ingeniería Informática
Al insertar una nueva fila, aquellos campos en los que no hayamos especificado el valor:
1. Si en el CREATE TABLE esos campos tienen un modificador DEFAULT, se les aplicará el valor por
defecto especificado.
2. Si esos campos no tuviesen DEFAULT tomarían el valor nulo.
Llegado a este punto, el proceso de inserción no ha terminado, pues el SGBD comprobaría cada una de las
restricciones que se hubiesen declarado (NOT NULLs, CHECKs, PRIMARY KEY, UNIQUEs, y REFERENCES). Si
al comprobar las restricciones el SGBD detecta el incumplimiento de alguna, la inserción finalmente no se realizará,
quedando la base de datos en el mismo estado que antes de hacer INSERT, a lo sumo lo único que notará el usuario es
un mensaje de error explicativo de que no se ha realizado la inserción debido a un intento de violar una determinada
restricción.
Si por el contrario, no se viola ninguna restricción, la inserción se lleva a cabo. No debes de asumir que esa fila va a
ser “la última” de la tabla, pues “teóricamente” no hay orden en los elementos de una tabla.
Al hacer una inserción de un valor numérico en un campo de menor precisión, el SGBD normalmente hará un
redondeo y lo insertará satisfactoriamente. Por ejemplo, al insertar 1,234 en un NUMERIC(3,2) lo redondearía a dos
decimales: 1,23.
Si al hacer la inserción de un valor numérico el SGBD se da cuenta de que no cabe en ese campo, porque su rango de
valores es menor, el SGBD rechaza la inserción y lanza un error al usuario. Por ejemplo, al insertar 12,34 en un
NUMERIC(3,2) devolvería error porque el 12 no cabe en la única posición que ese NUMERIC tiene reservada para
la parte entera de un número de 3 cifras de las cuales 2 son para los decimales.
Lo mismo ocurre si se intenta insertar una cadena de caracteres en un campo de menor longitud.
Por ejemplo, sea la tabla:
El SGBD rechazará la inserción porque '23-07-93' es una cadena, y el campo FechaMuestra es un DATE, por lo cual
hay un error de concordancia de tipos6. Sin embargo, no da error porque 92.85 no quepa en un NUMERIC( 3, 1),
pues el SGBD lo redondearía a 92.9.
Sin embargo en:
6 Hay sistemas -p.e. Oracle y las últimas versiones de PostgreSQL- que tienen conversión automática de tipos. Esto significa que
cuando se observa una discordancia de tipos como la del ejemplo, en lugar de dar un error, intenta convertir el valor al tipo
correspondiente, en este caso convertiría la cadena en fecha. Sin embargo, la conversión automática de tipos no es estándar.
Bases de Datos 21
Grado en Ingeniería Informática
no sólo habrá el consabido error de tipos, sino el correspondiente a que 101.44 no quepa en un NUMERIC( 3, 1).
Tampoco cabría 99.95, pues al redondearlo a un dígito decimal daría 100.0, y por tanto la inserción no se realizaría
dando un error de desbordamiento.
En el caso de:
también dará error, pues el literal cadena es de longitud 24, y el campo de longitud 13.
La inserción de literales podría añadir varias filas con una sola instrucción, basta con que cada fila vaya entre
paréntesis, y que cada fila vaya separada por comas de la siguiente forma. Por ejemplo:
Importante: Cuando se hace DROP TABLE, no sólo se borra la tabla, sino también todas las filas insertadas.
Ejercicio 6:
Abre PR2-01.sql, interpreta todos los comportamientos anómalos que se dan en los inserts de los 8 casos entre
comentarios. Diagnostica el problema en cada caso. ¿En qué casos el mensaje de error muestra el nombre de la
restricción violada?
Bases de Datos 22
Grado en Ingeniería Informática
Como vemos, el comando SELECT consta de cuatro clausulas: SELECT, FROM, WHERE y ORDER BY, que han de
ser especificadas en ese mismo orden. Las dos primeras son obligatorias, mientras que las dos segundas son
opcionales7.
Bases de Datos 23
Grado en Ingeniería Informática
Alumnos
Nombre Altura Peso
Pepe 1,70 67
Ana 1,72 67
Juan 1,70 83
SELECT * FROM Alumnos;
En el ejemplo lo que estamos pidiendo es que se nos muestren todos los campos de la tabla de alumnos; por lo tanto
se nos muestra el contenido de la tabla al completo.
Observa el carácter declarativo de la consulta: simplemente decimos lo que queremos que se muestre, y dejamos que
el algoritmo sea elegido por el SGBD.
Alumnos
Nombre Altura Peso
Pepe 1,70 67
Ana 1,72 67
Juan 1,70 83
Luis 1,70 83
SELECT Nombre, Altura FROM Alumnos;
Nombre Altura
Pepe 1,70
Ana 1,72
Juan 1,70
Luis 1,70
Lo normal no es que queramos que se muestren todos los campos de la tabla, sino sólo algunos, por ello el
modificador habitual de la clausula SELECT es una lista formada por esos campos. En la lista cada campo se separa
del siguiente mediante una coma.
En la ilustración vemos que en el resultado de la consulta sólo se devuelven las columnas pedidas.
La cláusula SELECT tiene un modificador opcional que puede tomar dos valores ALL o DISTINCT. Cuando
ponemos DISTINCT el SQL no nos muestra en el resultado filas repetidas, mientras que cuando ponemos ALL,
muestra todas las filas, aunque estén repetidas. Cuando no ponemos nada, es lo mismo que poner ALL, que es la
Bases de Datos 24
Grado en Ingeniería Informática
que
y el resultado sería (no tienen por qué salir las alturas precisamente en ese orden):
Altura
1,70
1,72
1,70
1,70
Como vemos, aunque 1,70 es un valor que se repite, se muestra en el resultado de la consulta tres veces.
Sin embargo, si hubiéramos puesto:
Altura
1,70
1,72
La diferencia entre DISTINCT y ALL es evidente cuando sólo mostramos un atributo. Cuando tenemos varios
tenemos que pensar en que lo que no se muestran son filas en las que los valores de “todos” los atributos coincidan
con los de otra fila que ya se haya seleccionado para mostrar. Por ejemplo:
o bien
Nos hubiera devuelto todos los valores de las columnas, tal cual. Pero para la tabla de la Figura 5:
Alumnos
Altura Peso
1,70 67
1,72 67
1,70 83
Donde vemos que sólo se nos devuelve una vez la tupla < 1,70, 83>, y no dos veces como en el caso del ALL.
Bases de Datos 25
Grado en Ingeniería Informática
Observa que no importa que el peso de los dos primeros alumnos sea el mismo, pues al ser sus alturas distintas, ya
son filas distintas del resultado.
Poner DISTINCT no es gratis, sino que penaliza gravemente el tiempo de respuesta de la consulta. Si a nosotros nos
pidieran quitar las cartas repetidas de una baraja, probablemente tendríamos que ordenar la baraja, lo que nos llevaría
un tiempo extra. Con las bases de datos pasa lo mismo. Por tanto, es bueno no utilizar el DISTINCT cuando no sea
necesario.
El caso típico, es que en nuestra SELECT estemos mostrando una clave primaria o un unique. Si fuese así, como los
valores de estas claves ya no se van a repetir en toda la tabla, no se van a repetir tampoco en las consultas que las
muestren. Por ejemplo:
Sin embargo, devolverían el mismo resultado8 asumiendo que quizás nombre es clave, y sus valores no se van a
repetir.
Como consecuencia, no tiene sentido poner:
si esa tabla (como ocurrirá normalmente) tiene clave primaria. Lo cual, no significa que no se pueda poner, sino que
es un derroche de tiempo de respuesta.
Por último, comentar que no sólo podemos extraer campos de la tabla sino expresiones correspondientes a cálculos.
Por ejemplo, podemos pedir el índice de masa corporal, la altura en pies, y el peso en libras de cada alumno.
En este sentido:
1. Los campos numéricos se pueden someter a sumas, restas, multiplicaciones y divisiones (además de otras
operaciones que facilite el SGBD como funciones exponenciales y trigonométricas) con los operadores +, -,
* y / respectivamente, y con los paréntesis para especificar la precedencia.
2. Los tipos fecha cuando se restan devuelven el número de días transcurridos entre ambas fechas.
3. Cuando se suma un entero a una fecha, el entero es interpretado como un número de días. Así por ejemplo,
mañana sería CURRENT_DATE+1.
4. Los SGBDs incorporan normalmente un buen repertorio de funciones de manejo de caracteres, pero al
menos debemos saber que el operador “||” (doble barra vertical) significa concatenación. Así 'Hola '||'Pepe'
es 'Hola Pepe'.
Bases de Datos 26
Grado en Ingeniería Informática
nos daría el literal “pies” y el literal “libras” concatenado a sus valores respectivos
( round ( cantidad, 2) se ha utilizado para redondear a dos decimales los resultados).
Un caso particular de expresión sería un literal. Por ejemplo, podríamos hacer:
lo que nos devolvería una fila por cada alumnos, de manera que cada fila fuese 'Hola Pepe', 'Hola Juan' etc.
Por tanto, aunque no muy útil, sí sería válida la consulta:
Que devolvería tantas filas como alumnos hubiese, pero todas las filas serían iguales, incluyendo únicamente cada
una de ellas la palabra 'Hola'.
Nos dará como resultado la altura y peso de los alumnos cuyo peso sea igual a 67:
Altura Peso
1,70 67
1,72 67
El esquema más sencillo de predicado es el formado por un campo (como por ejemplo peso), un comparador (como
por ejemplo “=”), y un literal o constante (como por ejemplo 67). Los comparadores (como ya vimos con el CHECK
en la sección 2.2.4) son =, !=, <>, <, >, <= o >=.
Otro esquema de comparación podría ser campo+comparador+campo. Por ejemplo: empleados cuyo coeficiente
intelectual fuera menor que su número de zapatos, supuesto que el CI y el número de zapatos 9 fueran atributos de la
tabla de empleados:
Bases de Datos 27
Grado en Ingeniería Informática
SELECT Nombre
FROM Empleados
WHERE CI<numZapatos;
En general, donde estamos poniendo campos podría haber una expresión, por ejemplo:
SELECT Nombre
FROM Empleados
WHERE CI<2*numZapatos;
o por ejemplo:
que preguntaría por los alumnos cuyo peso en kilos es inferior a los centímetros que exceden de 1 metro en su talla.
El predicado lógico puede ganar algo de complejidad a través de los conectores lógicos que pueden ser AND, OR y
NOT. Por ejemplo:
SELECT Nombre
FROM Alumnos
WHERE peso=67
AND altura=1.70;
Esta consulta devolverá el nombre de los alumnos que pesan 67 y miden 1.70, y en nuestro caso se trata únicamente
de Pepe.
La precedencia del NOT es mayor que la del OR y el AND, mientras que el AND mantiene mayor precedencia que el
OR. No obstante, podemos alterar la interpretación de la precedencia utilizando paréntesis. Así, la consulta:
SELECT Nombre
FROM Alumnos
WHERE (peso=67
AND altura=1.70)
OR peso>80;
es equivalente a:
SELECT Nombre
FROM Alumnos
WHERE peso=67
AND altura=1.70
OR peso>80;
Bases de Datos 28
Grado en Ingeniería Informática
SELECT Nombre
FROM Alumnos
WHERE peso=67
AND (altura=1.70
OR peso>80);
SELECT Nombre
FROM Alumnos
WHERE (peso=67 AND altura=1.70)
OR peso>80
AND NOT nombre = 'Juan';
Devuelve Pepe y Luis, pues es la misma consulta que devolvía Pepe, Juan y Luis a la que hemos añadido que no
queremos que el alumno se llame Juan. Podíamos haber formulado la misma consulta con “distinto”, en lugar de
“NOT igual”:
SELECT Nombre
FROM Alumnos
WHERE (peso=67 AND altura=1.70)
OR peso>80
AND nombre != 'Juan';
O bien:
SELECT Nombre
FROM Alumnos
WHERE (peso=67 AND altura=1.70)
OR peso>80
AND nombre <> 'Juan';
Bases de Datos 29
Grado en Ingeniería Informática
está todavía en disco, es muy probable que salga primero en el resultado Pepe.
Sin embargo, para un programador o un usuario es muy útil obtener la información de la base de datos en un
determinado orden. Para ello existe la cláusula opcional ORDER BY.
Antes de adentrarnos en el ORDER BY deberemos revisar cuál es el orden dentro de los distintos tipos de datos:
• En el caso de los datos numéricos la ordenación es trivial.
• En el caso de las fechas, deberemos de tener en cuenta que las fechas antiguas son menores que las
recientes, y estas a su vez, menores que las futuras.
• El caso de las cadenas de caracteres es el más complicado, pues se rigen según un criterio conocido como
orden lexicográfico basado en el código ASCII, consistente en:
• El espacio en blanco es menor que los signos de puntuación.
• Los signos de puntuación menor que los dígitos.
• Los dígitos menores que las mayúsculas.
• Las mayúsculas menores que las minúsculas.
Comentario: Antiguamente los caracteres extendidos propios de los diversos
alfabetos nacionales salían al final de la tabla ASCII, por lo que erróneamente
trataba a la “ñ” como mayor que la “z”. En la actualidad todos estos problemas están
subsanados.
Por lo tanto, la consulta:
SELECT Nombre
FROM Alumnos
WHERE nombre >= 'Juan';
nos devolverá los alumnos Juan, Pepe y Luis, pues al empezar los nombres por P o L ya son mayores que Juan. Juan
sale en el resultado por ser igual a si mismo. También podríamos haber formulado la consulta como:
SELECT Nombre
FROM Alumnos
WHERE NOT nombre < 'Juan';
Cuando una cadena está contenida al principio de otra cadena, la primera de estas dos es la menor. Así 'Juan' está
contenida al principio de 'Juanito' por lo que 'Juanito' es mayor que 'Juan'.
Visto como se definen los órdenes en los tipos de datos que vamos a manejar en SQL, nos adentramos ya en la
clausula ORDER BY. El caso más sencillo sería que quisiésemos ordenar crecientemente por un determinado campo.
Por ejemplo:
SELECT Nombre
FROM Alumnos
ORDER BY altura;
Bases de Datos 30
Grado en Ingeniería Informática
Nombre
Pepe
Juan
Luis
Ana
Y decimos que “quizás”, pues es válido cualquier otro orden con tal de que Ana quede la última (recuerda que Ana
medía 1,72 y los chicos todos 1,70).
Es posible especificar órdenes anidados, por ello el modificador del ORDER BY es una lista de criterios separados
por comas. Por ejemplo, podemos querer que si dos o más alumnos tienen la misma estatura, salgan ordenados por
peso:
SELECT Nombre
FROM Alumnos
ORDER BY altura, peso;
En cuyo caso el resultado saldría en el orden Pepe, Luis, Juan y Ana o bien Pepe, Juan, Luis, y Ana (ya que Juan y
Luis pesan y miden lo mismo).
Lógicamente, el ORDER BY se puede combinar con el WHERE:
SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura, peso;
SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura DESC, peso;
Primero pondría a los altos: Ana, y luego entre los que tienen la misma altura, primero pondría a los menos pesados:
Pepe y Luis, por este orden. Otros ejemplos:
SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura DESC, peso DESC;
Bases de Datos 31
Grado en Ingeniería Informática
SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura, peso DESC;
SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura ASC, peso DESC;
SELECT Nombre
FROM VotantesUE
ORDER BY país, región, provincia, población,
CP, Edad DESC;
Ejercicio 7:
Toma la tabla creada en PR2_03.sql y haz las consultas propuestas en su interior guardando el script con las
soluciones en PR2_04.sql.
de manera que borraría de la tabla cuyo nombre especificamos aquellas filas que cumpliesen la condición. La
condición sería completamente igual que la condición WHERE de una SELECT. Por ejemplo:
Bases de Datos 32
Grado en Ingeniería Informática
borraría de la tabla de alumnos todas las filas con el campo peso con valor mayor que 70.
La condición WHERE es una clausula optativa, que caso de omitirse tendría como resultado el borrado de todas las
filas de la tabla. Por ejemplo:
La cláusula SET permite especificar qué columnas van a ser modificadas y con qué valor. Por ejemplo:
UPDATE alumnos
SET altura=1.90, peso=90
WHERE nombre='Pepe';
asignaría a los alumnos que se llamen Pepe una talla de 1.90 y un peso de 90 Kgs.
Las asignaciones no sólo pueden ser de literales, sino que pueden incluir expresiones con cálculos, por ejemplo:
UPDATE alumnos
SET altura=1.90, peso=peso*1.20
WHERE nombre='Pepe';
UPDATE alumnos
SET peso=peso*1.20;
subiría de peso a todos los alumnos un 20%. Observa que el ejemplo además ilustra que la lista de campos a
actualizar podría estar formada por un único campo.
Otro ejemplo: supongamos que nuestro SGBD tenga una función UPPER(<cadena>) que pasa a mayúsculas esa
cadena. Entonces:
UPDATE alumnos
SET nombre=upper(nombre);
Bases de Datos 33
Grado en Ingeniería Informática
pasaría a mayúsculas los valores del campo nombre para todos los alumnos.
Comentario: (extraído de [Celko 2005]) La sentencia UPDATE permite
intercambios de valores de campos sin necesidad de variables intermedias como
ocurre con los lenguajes procedurales. Así para intercambiar los valores de los
campos a y b de la tabla T, basta con hacer:
UPDATE T SET a = b, b = a;
UPDATE T SET a = b;
UPDATE T SET b = a;
al final conseguiríamos que ambos campos tuviesen los mismos valores, que en este
caso serían los valores de b.
Finalmente, nota que las reglas que se aplicaban en el INSERT en lo referente a desbordamiento de valores, también
se aplican al UPDATE. Es decir, si se trata de valores numéricos y no hay suficiente precisión en el campo, no da
error y redondea, pero si no hay suficiente rango da error. De la misma forma, si son valores cadena, y el campo no
tiene la longitud suficiente el SGBD daría error.
En este caso el SGBD ejecutará la SELECT, obteniendo una tabla temporal que el usuario no ve con los campos
<nombre, altura/0.3048> y tantas filas como verifiquen el predicado WHERE. Con ese resultado tratará de insertar
en altos tantas filas como tenga esa tabla temporal, de manera que al campo nombre de alumnos iría a parar el valor
de nombre de altos, a pies iría a parar el valor de la expresión altura/0.3048 que pasa los metros a pies.
Observa que con este tipo de inserción no sólo puedes insertar varias filas simultáneamente, sino que podría darse el
caso de que no insertases ninguna porque el predicado WHERE de la SELECT no sea verificado por ninguna fila de
la tabla de origen.
Bases de Datos 34
Grado en Ingeniería Informática
que lo que hace es crear una tabla altos con los campos nombre y pies que tomarán respectivamente los valores de los
campos nombre y la conversión a pies del campo altura de los alumnos que miden más de 1.70. Por lo que podíamos
pensar, que podíamos haber hecho lo mismo en dos pasos de la siguiente manera:
y lo cierto es que efectivamente en muchos casos el resultado sería el mismo. Sin embargo, habría casos en los que –
como en este – no daría lo mismo. En concreto en la tabla que hemos creado en un solo paso no hemos dicho en
ningún momento cuáles son los tipos de cada uno de los campos, ni hemos dicho qué restricciones tiene la tabla, ni
por extensión sus campos (e.g.,la PRIMARY KEY).
En cuanto a los tipos, normalmente intenta heredar los tipos de los campos de los que proviene. Es decir el campo
nombre sería un CHAR(10) porque nombre es CHAR(10) en la tabla alumnos, pero el campo pies sería un
NUMERIC con toda la precisión posible, porque en la división no está claro cuantos decimales tomaría. Además, el
nombre es PRIMARY KEY en alumnos, pero no podemos asumir que ningún SGBD vaya a hacer que altos haga que
nombre sea PRIMARY KEY. Sin embargo, ese efecto lo podemos conseguir con la formulación en dos comandos, de
manera que en el CREATE TABLE especifiquemos explícitamente que nombre es PRIMARY KEY.
En cuanto a la sintaxis, la lista de campos es optativa, de manera que el comando:
es correcto, pero en ese caso la tabla altos tendría los campos nombre y otro campo al que el SGBD le daría el
nombre que quisiera según su entender.
Bases de Datos 35
Grado en Ingeniería Informática
Por ejemplo:
Crearía una vista con los mismos campos y filas que el CREATE TABLE AS SELECT de la sección anterior. Sin
embargo, asumiendo que es Ana la única alumna que mide más de 1.70, si borrásemos a Ana de la tabla de alumnos,
la consulta:
Seguiría dando una fila si altos es la tabla de CREATE TABLE AS SELECT, pues al crearse como una copia de
alumnos, tiene sus propias filas, y hemos borrado una fila que no es suya, que es de alumnos. Pero esta misma
SELECT no devolvería ninguna fila en el caso de que altos fuese la vista, porque la vista no tiene filas propias, y las
recalcula cada vez que tiene que mostrarlas, y como alumnos ya no tiene a Ana, la vista altos tampoco la tendría.
La lista de campos también es opcional, y podríamos haber creado la vista así:
pero no tendríamos control sobre el nombre que el SGBD elegiría para el segundo campo de la vista.
Las vistas se borran mediante DROP VIEW:
SQL no permite que borremos la tabla en la que se basa una vista si no borramos la vista primero. Por tanto, para
hacer
Bases de Datos 36
Grado en Ingeniería Informática
Bases de Datos 37
Grado en Ingeniería Informática
);
La palabra clave REFERENCES es la que indica que numEstudio es una clave ajena. Se trata de una restricción de
campo, y como restricción prohíbe ciertas cosas:
1. Si insertamos una fila en la tabla hija que no se corresponde con ninguna fila de la tabla padre, el sistema
devuelve error (e.g.; no podemos insertar una estrella cuyo campo numEstudio tenga un valor que no esté
en la tabla de estudios).
2. Si modificamos el valor de la clave ajena en la tabla hija, a un nuevo valor que no se corresponde con
ninguna fila de la tabla padre, el sistema devuelve error (e.g.; no podemos modificar el estudio de una
estrella a un nuevo valor tenga que no esté en la tabla de estudios).
3. Si borramos una fila de la tabla padre que tiene filas hijas, el sistema devuelve error (e.g., no podemos borar
un estudio con estrellas).
4. Si modificamos el valor de la clave primaria en la tabla padre, de una fila que tiene filas hijas, el sistema
devuelve error (e.g., no podemos cambiar en la tabla de estudios, el número de estudio de un estudio que ya
tuviese estrellas).
En definitiva el sistema cuida que toda fila de la tabla hija tenga un padre en la tabla padre y nunca quede huérfana
(e.g.; no puede haber estrellas que tengan en el campo numEstudio un valor que no esté en la clave primaria de
Estudios11). Es por tanto una restricción, que ya en el tema pasado la dimos el nombre de restricción de integridad
referencial.
Los dos últimos comportamientos de la lista anterior (borrado y actualización sobre filas de la tabla padre) pueden
modificarse con las opciones ON DELETE y ON UPDATE respectivamente haciendo cosas distintas a devolver
error, como veremos a continuación, mientras que los dos primeros (borrado y actualización sobre filas de la tabla
hija) siempre devuelven error.
Como toda restricción SQL, las restricciones de clave primaria, pueden o no tener nombre, pueden declararse junto al
campo o pueden ser de tabla. En el caso del ejemplo se ha declarado junto al campo y con nombre, pero también se
podría haber declarando la clave ajena fuera de línea al final de la tabla. Cuando se declara al final de la tabla hay que
añadir la palabra clave FOREIGN KEY. Por ejemplo:
11 Hay una pequeña excepción a este comportamiento que trataremos más adelante ( numEstudio de la tabla estrellas podría tomar
el valor nulo mientras no especifiquemos de forma explícita que ese campo es NOT NULL)
Bases de Datos 38
Grado en Ingeniería Informática
En ambos casos podíamos opcionalmente haber omitido los nombres de las restricciones.
Las dos declaraciones hechas hasta ahora hubieran sido equivalentes a añadir las opciones ON DELETE/ON
UPDATE con el modificador NO ACTION. Por ejemplo:
O bien
Bases de Datos 39
Grado en Ingeniería Informática
Sin embargo, podríamos haber querido que cuando se borre un estudio, se borrasen en la tabla de estrellas, todas las
estrellas de ese estudio. Esto se conoce como borrado en cascada. En este comportamiento, cuando se borra un
elemento de la tabla padre se eliminan en cascada todas las filas hijas de éste en la tabla hija.
El borrado en cascada mantiene la integridad referencial, no hay filas en la tabla de estrellas que no referencien a un
estudio que no exista, pues si borro el estudio, borro sus estrellas, y estas ya no quedan huérfanas en la relación.
Sintácticamente, esto se haría con ON DELETE CASCADE. Por ejemplo:
O bien
Bases de Datos 40
Grado en Ingeniería Informática
Puesto que el ON UPDATE NO ACTION no hace falta ponerlo, ya que es la opción por defecto. También hubiera
dado lo mismo hacer de esta otra forma:
Bases de Datos 41
Grado en Ingeniería Informática
De manera similar, podríamos hacer que cuando el número de estudio cambie en la tabla de estudios, las estrellas de
ese estudio cambiasen el campo numEstudio al nuevo valor, con el fin de seguir estando asociadas al mismo. Esto se
conoce como actualización en cascada. La actualización en cascada cambia los valores de las claves ajenas en las
filas hijas, cuando la fila padre cambia el valor de la clave primaria preservando que los hijos sigan referenciando al
mismo padre, y por tanto, manteniendo la integridad referencial al no quedar huérfanos. La actualización en cascada
se hace con ON UPDATE CASCADE. Por ejemplo:
Bases de Datos 42
Grado en Ingeniería Informática
Podríamos haber declarado que ambos comportamientos (delete y update) fuesen en cascada:
Y podíamos haber declarado la clave ajena fuera de línea o de tabla, como en ocasiones anteriores, pero lo dejamos
para el alumno por ser demasiado obvio.
Comentario: Además, de NO ACTION y CASCADE existen otros dos
comportamientos, si bien son mucho menos habituales, a saber: SET NULL, y SET
DEFAULT:
Bases de Datos 43
Grado en Ingeniería Informática
ON DELETE SET NULL: Cuando se borra una fila de la tabla padre, se ponen a
null los valores de la clave ajena en las filas hijas. Por tanto, no mantiene
propiamente la integridad referencial, en el sentido de que las filas hijas quedan
huérfanas, pero al menos no apuntan a un padre que no existe, sino que apuntan a
null, que es como no apuntar a nadie. Ten cuidado, si algún campo de la clave ajena
lo has declarado como NOT NULL, no podrás utilizar esta opción, por ser
(obviamente) incompatible.
ON UPDATE SET NULL: Cuando se modifica el valor de la clave primaria en una
fila de la tabla padre, se ponen a null los valores de la clave ajena en las filas hijas.
Por tanto, ocurre los mismo que con ON DELETE SET NULL: no mantiene
propiamente la integridad referencial, en el sentido de que las filas hijas quedan
huérfanas, pero al menos no apuntan a un padre que no existe, sino que apuntan a
null, que es como no apuntar a nadie. Ten cuidado, si algún campo de la clave ajena
lo has declarado como NOT NULL, tampoco podrás utilizar esta opción, por ser
incompatible.
ON DELETE SET DEFAULT: Para poder utilizarlo, todos12 los campos de la clave
ajena deben de tener declarados el valor por defecto (clausula DEFAULT). Cuando
se borra una fila de la tabla padre, los valores de la clave ajena en las filas hijas
toman el valor por defecto. Obviamente, es necesario que exista en la tabla padre
una fila con ese valor por defecto en la clave primaria. Por tanto, mantiene
propiamente la integridad referencial, en el sentido de que las filas hijas quedan
huérfanas de su padre actual, pero apuntan a un padre que existe y que se encarga de
acoger a todas las huérfanas. En ese sentido si hubiéramos declarado DEFAULT
NULL, es como si directamente hubiésemos hecho ON DELETE SET NULL.
ON UPDATE SET DEFAULT: Lo mismo que en el caso anterior pero para ON
UPDATE.
En la práctica SET NULL y SET DEFAULT casi nunca se usan. Es más, existen
muchos SGBDs que ni siquiera lo implementan.
Por último, varias observaciones:
1. En los ejemplos estamos declarando primero ON DELETE y luego ON UPDATE, pero el orden es
indistinto, podría haber sido al revés.
2. Si la clave primaria de la tabla padre es compuesta, la clave ajena de la tabla hija también lo será y tendrá
declarados los mismos campos (aunque podrían tener distintos nombres) en el mismo orden que se
declararon en la clave primaria. Al ser una clave compuesta es obligatoria declararla fuera de línea (es
decir, como restricción de tabla). Por ejemplo:
12 No es que de error si no tienes declarados los valores por defecto, sino que luego lo que va a hacer es actuar como si hubieses
declarado DEFAULT NULL.
Bases de Datos 44
Grado en Ingeniería Informática
en donde vemos que el nombre y apellidos del protagonista forman una clave ajena que prohíbe introducir
protagonistas que no estén en la tabla de estrellas. Como en esa tabla nombre, apellido1 y apellido2 eran la
clave primaria (en ese orden), la clave ajena, al ser compuesta, hay que declararla al final, y tendrá también
esos campos, con los mismos tipos (CHAR(35)) y en ese orden:
si bien vemos que es posible llamarlos de manera distinta (ver sufijo “_prota”).
Si no respetas el orden, probablemente el SGBD no daría error, pero tendría consecuencias no deseadas.
Por ejemplo la clave ajena:
comprobaría que ape1_prota tuviese el mismo valor que el campo nombre de estrellas y que ape2_prota
tuviese el mismo valor que el campo ape1 de estrellas, y que nombre_prota tuviese el mismo valor que
ape_2 de estrellas, ya que confronta los distintos campos de ambas claves (la primaria y la ajena) según el
orden en el que aparezcan al definir esas claves.
3. Al borrar una tabla padre con DROP TABLE, las filas de las tablas hijas quedarían huérfanas, por ello el
sistema nunca dejara que borres una tabla padre, tendrás que:
1. O bien borrar primero las tablas hijas y luego sus padres.
2. O bien utilizar la opción CASCADE CONSTRAINTS de DROP TABLE. Por ejemplo:
que permite borrar la tabla estudios, a la que estaba ligada la tabla de estrellas, porque de manera
automática borra, además de la tabla, las declaraciones de clave ajenas que hubiera en sus tablas hijas.
Es decir, la tabla hija seguirá existiendo con todas sus filas, pero es como si no hubiésemos declarado
los FOREIGN KEY-REFERENCES en ella. Por ejemplo al hacer el anterior DROP TABLE la tabla
Bases de Datos 45
Grado en Ingeniería Informática
de estrellas persiste pero una vez hagamos ese DROP TABLE CASCADE nos dejará meter filas cuyo
estudio no exista en la tabla de estudios, (de hecho ya no existe la tabla de estudios).
IMPORTANTÍSIMO: La clave ajena no implica una restricción NOT NULL, es decir, si no pones de manera
explícita una restricción NOT NULL en los campos que conforman una clave ajena, estos campos podrían
tomar el valor nulo. Esta cuestión puede resultar sorprendente desde el punto de vista del mantenimiento de la
integridad referencial, pues esta impide que una fila hija quede huérfana, y no declarando como NOT NULL los
campos de la clave ajena excepcionalmente sí que podrían quedar huérfanas alguna filas.
Por ejemplo, en nuestro caso, una estrella podría no tener estudio si el campo numEstudio tomase el valor nulo;
y una película podría no tener protagonista si sus campos nombre_prota, ape1_prota y ape2_prota tomaran el
valor nulo. Puede haber ocasiones en las que esta situación nos convenga, y no declaramos los NOT NULL, y
puede haber situaciones en las que sea un inconveniente y tengamos que declarar los NOT NULL.
IMPORTANTÍSIMO: Ten cuidado con el orden en el que creas y borras las tablas, si la tabla B tiene una clave
ajena que referencia a A (i.e., B es una tabla hija de A) tienes que:
1. Declarar A antes que B para que el SGBD no proteste al crear B diciendo que la tabla A aún no existe.
2. Borrar B antes que A para que el SGBD no proteste al dejar huérfanas a las hijas de B (o bien, hacer
el DROP TABLE con la opción CASCADE).
En nuestro ejemplo hay que crear primero los estudios, luego las estrellas y finalmente las películas; y si no
usamos la opción CASCADE en el DROP TABLE, el orden de borrado sería el contrario: primero las películas,
luego las estrellas y finalmente los estudios.
Ejercicio 9:
Haz un script SQL que implemente el esquema relacional que representa la Figura 6, que a su vez está basado en los
esquemas que se utilizaron de ejemplo en el tema anterior, al que se ha añadido la tabla Notas que representa qué nota
obtiene cada alumno en cada asignatura.
Declara las restricciones de manera que :
1. Cuando cambie el IdAlumno de un alumno se cambie automáticamente en la tabla de teléfonos.
2. Cuando se borre un alumno se borren sus teléfonos
Además:
1. Inserta 3 filas de prueba en cada tabla, comprobando que se verifican todas las restricciones.
2. Haz un UPDATE que ilustre que al cambiar el IdAlumno en alumnos, cambia también en teléfonos.
3. Haz un DELETE que ilustre que al borrar un alumno, se borran también los teléfonos.
Responde a estas otras preguntas, bien con UNO o con VARIOS:
1. Cuantos alumnos pueden estar en la misma asignatura
2. En cuantas asignaturas podría estar matriculado (sacar nota) un alumno
3. Cuantas asignaturas puede impartir como máximo un profesor
4. Cuantos profesores podrían impartir la misma asignatura
5. Cuantos teléfonos puede tener un alumno
6. Cuantos alumnos pueden tener el mismo teléfono
Bases de Datos 46
Grado en Ingeniería Informática
FK
TeléfonosAlumnos ( IdAlumno, teléfono )
PK
FK FK
Notas ( IdAlumno, IdAsignatura, IdTitulación, Nota )
PK
IV. Resumen
En este tema hemos revisado los comandos SQL que permiten crear y borrar tablas, insertar filas, borrarlas y
modificarlas. Hemos visto muy preliminarmente el comando SELECT que permite hacer consultas, pues su
versatilidad es tal que requiere un capítulo por si mismo, como veremos en temas posteriores.
V. Glosario
BNF. La sintaxis BNF (Backus – Naur Form) sirve para especificar las reglas sintácticas de un lenguaje, típicamente
un lenguaje de programación. En este tema BNF aparece relacionado a la sintaxis de algún comando SQL. De
momento tienes que saber que:
1. Todo los que va entre corchetes [ … ] en BNF significa que es opcional. Por ejemplo la clausula WHERE
de la SELECT.
2. La barra | significa alternativas, por ejemplo en la SELECT la parte [DISTINCT|ALL], sólo puede tomar
dos valores u opciones, o ponemos DISTINCT, o ponemos ALL (o no ponemos nada ya que además es
opcional por ir entre corchetes).
Clausula SQL. Es cada una de las partes principales de un comando. El comando SELECT hasta donde hemos visto
en este tema consta de cuatro clausulas ( SELECT, FROM, WHERE y ORDER BY).
Clave primaria. Conjunto de campos que se utilizan para identificar de forma univoca cada fila de una tabla. Puede
ser simple, si está formada por un solo campo, o compuesta si está formada por varios
Bases de Datos 47
Grado en Ingeniería Informática
Especificación de campo. Parte de la declaración del comando create table SQL que sirve para describir un campo
de una tabla. Obligatoriamente consta de nombre de campo y tipo de datos del mismo, opcionalmente consta de valor
por defecto y lista de restricciones. Todas las especificaciones acaban en coma, salvo la del último campo si no va
seguido de restricciones de tabla.
Lenguaje declarativo. Es un lenguaje en el que no especificamos un algoritmo para obtener el resultado, sino que
directamente especificamos qué debe de cumplir el resultado.
Literal. Un literal es un valor concreto que puede tomar un atributo de un determinado tipo. Es similar a lo que en un
lenguaje de programación clásico es una constante. Por ejemplo, el literal numérico 5, o el literal cadena 'hola' o el
literal fecha DATE '05-08-2015'.
Precedencia. Relativo a un operador. Se dice que un operador P tiene precedencia sobre otro Q, si en ausencia de
paréntesis, P se evalúa antes que Q, incluso si Q aparece antes que P en una expresión que los contenga de forma
simultanea. Por ejemplo, en la expresión 1+3*2 puede observarse que la multiplicación “*” tiene precedencia sobre
la suma “+”, pues en ausencia de paréntesis el resultado de la multiplicación se evaluaría antes que el de la suma.
Restricción de columna o de campo. Es aquella que se declara en la especificación del campo con idea de que se
comprueba al cambiar el valor de ese campo o al darle valor por primera vez.
Restricción de tabla. Es aquella que se declara de forma independiente a los campos, normalmente al final de la
tabla. Son necesarias para declarar restricciones en las que interviene más de un campo y se chequean tanto en las
inserciones, como al finalizar el cambio de todos los campos de una fila.
VI. Bibliografía
Referencias:
[Celko 2005] Celko, J. SQL for Smarties 3rd Ed.. Morgan Kaufmann, 2005.
(Disponible en acceso abierto en https://datubaze.files.wordpress.com/2015/03/celkos-sql-for-smarties-2005.pdf).
[Connolly y Begg 2005]. Connolly, Thomas M. y Begg, Carolyn E. Sistemas de Bases de Datos
4ª ed. Pearson, 2005.
(Disponible en UBUvirtual: http://0-www.ingebook.com.ubucat.ubu.es/ib/NPcd/IB_BooksVis?
cod_primaria=1000187&codigo_libro=2155)
[Melton y Simon 1993] Melton, Jim y Simon, Alan R. Understanding the new SQL: a
complete guide. Morgan Kauffman Publishers Inc. 1993.
Bases de Datos 48
Grado en Ingeniería Informática
Bases de Datos 49
Grado en Ingeniería Informática
Licencia
Autor: Jesús Maudes Raedo
Área de Lenguajes y Sistemas Informáticos
Departamento de Ingeniería Civil
Escuela Politécnica Superior
UNIVERSIDAD DE BURGOS
2015
Este obra está bajo una licencia Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 Unported. No se
permite un uso comercial de esta obra ni de las posibles obras derivadas, la distribución de las cuales se debe hacer
con una licencia igual a la que regula esta obra original
Licencia disponible en http://creativecommons.org/licenses/by-nc-sa/3.0/
Bases de Datos 50