0% encontró este documento útil (0 votos)
31 vistas50 páginas

Tema 2

Cargado por

miyof39277
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 PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
31 vistas50 páginas

Tema 2

Cargado por

miyof39277
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 PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 50

Grado en

Ingeniería
Informática

BASES DE DATOS

TEMA 2
Primeros pasos con SQL

Docentes:

Jesús Maudes Raedo


Índice de contenidos
I.INTRODUCCIÓN..................................................................... 3
II.OBJETIVOS.......................................................................... 3
III.CONTENIDOS ESPECÍFICOS DEL TEMA...............................3
1.El lenguaje SQL..................................................................4
1.1.Programación de Scripts SQL........................................... 4
1.2.Comentar líneas en un script SQL..................................... 5
1.3.Importancia de los Scripts SQL........................................ 5
2.Comandos SQL básicos y tipos de datos SQL.....................5
2.1.DROP TABLE................................................................. 5
2.2.CREATE TABLE básico..................................................... 6
2.2.1Principales Tipos de Datos en SQL............................... 7
2.2.2El valor NULL.......................................................... 10
2.2.3Sintaxis de la Definición de Columna..........................12
2.2.4Restricciones de Columna o de Campo....................... 13
2.2.5Nombrar las Restricciones........................................ 14
2.2.6Declaraciones de Restricciones de Tabla o Fuera de Línea
................................................................................... 16
2.3.El Comando INSERT..................................................... 20
2.4.La SELECT Básica......................................................... 22
2.4.1La Clausula WHERE................................................. 27
2.4.2Ordenación de la Consulta........................................ 29
2.5.Eliminación de filas con DELETE..................................... 32
2.6.Modificaciones de valores con UPDATE............................ 33
2.7.INSERT con sub-SELECT............................................... 34
2.8.CREATE TABLE AS SELECT............................................. 34
3.CREATE VIEW y DROP VIEW............................................35
4.Declaración de claves ajenas...........................................37
IV.RESUMEN........................................................................... 47
V.GLOSARIO........................................................................... 47
VI.BIBLIOGRAFÍA..................................................................48
VII.MATERIAL COMPLEMENTARIO.........................................49
Grado en Ingeniería Informática

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.

III. Contenidos específicos del tema

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.

1.1. Programación de Scripts SQL


El SQL se utiliza bien de forma interactiva o dentro de programas de aplicación. Cuando se utiliza de forma
interactiva, el usuario manda una petición a través de una interfaz en la que teclear la consulta o petición SQL, el
sistema le responde. Es básicamente como utilizaremos SQL durante el curso. Cuando lo utilizamos dentro de un
programa escrito por ejemplo en Java, C o cualquier otro lenguaje; esos lenguajes tendrán librerías que permitirán
incrustar comandos SQL dentro del código fuente, lanzar esas peticiones SQL a la base de datos y procesar la
respuesta que la base de datos dé. La utilización de SQL de esta última forma se corresponde con la asignatura
Aplicaciones de Bases de Datos que cursarás en tercero.
Dentro de la utilización interactiva, nos ocurrirá a menudo que nos equivoquemos al teclear una consulta. A veces esa
consulta es muy larga, y es enojoso volver a tener que teclearla, a lo mejor, simplemente porque hayamos bailado una
letra. Por eso, es mejor teclear la consulta en un fichero y pedir al sistema que ejecute el fichero. Así, si nos
equivocamos no hay que teclear la consulta por entero, sino simplemente modificar lo que esté mal en ese fichero.
Un script SQL es un fichero de texto que contiene varios comandos en lenguaje de base de datos SQL. Los scripts
suele tener la extensión de fichero “.sql” y se pueden ejecutar desde algún intérprete de comandos sql que nos provea
nuestro SGBD. En nuestro caso ejecutaremos los scripts desde pgAdmin III. Veamos un ejemplo:
1. Con el notepad++, vi o cualquier otro editor de texto abre el fichero PR1_01.sql que se provee con el
material. Ahora no entiendes nada de lo que hace, pero basta que compruebes que es un fichero de texto
normal y corriente. Parece que crea una tabla de alumnos con las notas de un examen, e inserta 3 de ellos.
Cierra el fichero.

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.

3. Pulsa el botón para ejecutar el script.


Vamos a comprobar el resultado haciendo una consulta. Haz Archivo > Nueva ventana y teclea

SELECT * FROM examen;

pulsa el botón de ejecutar, y verás en la parte inferior las tres filas.


SELECT es un comando con muchas opciones, de momento ves que poniendo “SELECT * FROM” y detrás el

Bases de Datos 4
Grado en Ingeniería Informática

nombre de la tabla, puedes ver todos su contenido.


Ahora puedes guardar esta consulta en otro script. Haz Archivo > Guardar y llámala PR1-02.sql. Puedes cerrar esa
ventana y recuperarla más adelante.

1.2. Comentar líneas en un script SQL


Los convenios que sigue postgreSQL son:
1. El doble guión “--” comenta la línea actual.
2. Para comentar varias líneas encerraremos el texto entre “/* */”

1.3. Importancia de los Scripts SQL


Los scripts SQL se utilizan mucho para hacer instalaciones de bases de datos, y todo tipo de operaciones de
administración de bases de datos (crear cuentas de usuarios, copias de seguridad etc.).
Como alumnos, la ventaja mayor de trabajar con scripts es que si nos equivocamos al teclear una consulta, no
tendremos que teclearla toda desde el principio, sino que bastará con abrir el fichero, cambiar lo que esté mal, guardar
los cambio y pedir su re-ejecución.
Además por cuestiones de seguridad, las bases de datos instaladas en el aula están vacías, y al apagar el ordenador
vuelven a vaciarse, luego si queremos el próximo día tener la base de datos en el mismo estado que el día anterior
tenemos que ejecutar todos los comandos SQL del día anterior. Si tuviéramos que teclearlos uno a uno tardaríamos
mucho tiempo, pero si los tenemos guardados en un fichero de script, bastará con ejecutar el fichero para recuperar la
base de datos del día anterior en apenas unos segundos.
Es más, el profesor te proveerá de scripts durante las prácticas que tendrás que ejecutar. Por ejemplo te puedo dar un
script que cree unas tablas y las llene de datos, y luego proponerte como ejercicio que ejecutes consultas sobre esos
datos.

2. Comandos SQL básicos y tipos de datos SQL

2.1. DROP TABLE


Intenta ejecutar otra vez PR1_01.sql, ¿por qué ya no funciona?. Esta intentando volver a crear una tabla examen, pero
ya existe una que ya se llama así. En una base de datos no puede haber dos tablas que se llamen igual.
El siguiente comando SQL que vamos a mostrar es el que permite eliminar tablas de la base de datos, y se llama
DROP TABLE. Por ejemplo:

drop table EXAMEN;

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

DROP TABLE IF EXISTS examen;

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.

2.2. CREATE TABLE básico


En cada tabla varios de los campos (normalmente solo uno) se eligen para identificar unívocamente cada fila. Es decir
estos campos o campo, no toman nunca valores repetidos y nunca están vacíos. Este conjunto de campos es la clave
primaria de la tabla.
Cuando una clave primaria está formada por un solo campo diremos que es simple, y cuando está formada por varios
es compuesta. Un ejemplo de clave primaria simple es el código de la oficina si todas las oficinas tienen un código
distinto, Pero si sólo tienen código distinto las que son de la misma ciudad, entonces la clave primaria estaría formada
por el código y la ciudad, y sería compuesta. Date cuenta que en este segundo caso si que puede haber dos oficinas
con el mismo código, lo que no puede haber es dos oficinas que a la vez tengan el mismo código y sean de la misma
ciudad.
El comando DDL que permite crear tablas es CREATE TABLE. En PR1-04.sql tienes:

CREATE TABLE Oficinas (


Cod INTEGER PRIMARY KEY,
ciudad CHAR(15),
objetivo NUMERIC( 7, 2) DEFAULT 0.0 NOT NULL
);

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:

Create table OFICINAS (


COD integer PrImArY kEy,
CIUDAD char(15),
OBJETIVO numeric( 7, 2) DEfAuLT 0.0 not NULL
);

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:

Create table OFICINAS ( COD


integer
PrImArY kEy, CIUDAD char(15), OBJETIVO
numeric( 7, 2)
DEfAuLT 0.0 not NULL);

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.

2.2.1 Principales Tipos de Datos en SQL


Como hemos visto, en un CREATE TABLE existe una lista de especificaciones de campo separadas por comas. Cada
especificación de campo ha de tener obligatoriamente, y en este orden, un nombre de campo y un tipo de campo (por
ejemplo: cod integer).
Por tanto, lo primero que tenemos que saber para hacer nuestros primeros CREATE TABLEs, es qué tipos de datos se
admiten en SQL. Los que vamos ha contar aquí son los más utilizados. En concreto, para empezar debemos conocer.
• Cadenas de Caracteres: Se pueden especificar de dos maneras distintas: CHAR (n ) o VARCHAR (n ),
donde n es un entero mayor que cero que representa la longitud máxima que puede tomar dicha cadena.
Distinguir cuando conviene declarar un campo como CHAR o como VARCHAR se correspondería con
cursos avanzados. De momento ambos tipos nos parecerán equivalentes.

Bases de Datos 7
Grado en Ingeniería Informática

Comentario: Si vas a asignar la cadena 'Pepe' a un CHAR(8), el sistema


internamente guardará 'Pepe' más cuatro espacios detrás, hasta completar la longitud
ocho. Esto puede parecer un desperdicio de espacio, que a través de muchos campos
CHAR de muchas filas se traduce en que la base de datos ocupe mas. El principal
problema de una base datos que ocupa más, es que se tarda más tiempo en buscar
información en ella, porque el tanto por ciento de la misma que cabe en memoria es
menor, y la probabilidad de tener que hacer una o varias lecturas de disco para
obtener un dato aumenta (el acceso a disco es mucho más lento que a memoria). En
ese sentido puedes pensar que es más óptimo utilizar VARCHAR(8), de manera que
cuando asignes 'Pepe' sólo ocupe cuatro caracteres. El problema es que detrás de
'Pepe' seguro que va otro valor de otro campo (por ejemplo la edad que vale 18), y si
Pepe pasa a llamarse Antonio, en el VARCHAR(8) sólo nos caben las cuatro
primeras letras pues no queremos perder ese 18, mientras que con CHAR(8) habría
cabido por entero, e incluso nos habría sobrado un espacio. Eso no significa que ese
campo no pueda valer Antonio, sino que para escribir Antonio, tendría que hacer
algo especial, como por ejemplo borrar la fila donde figuraba 'Pepe' y volver a
recrearla con el valor 'Antonio'.
Conclusión: utiliza VARCHAR cuando veas que el dato no es probable que cambie
(por ejemplo, el nombre, la provincia de nacimiento, ...), y CHAR cuando veas que
va a cambiar frecuentemente (por ejemplo, la dirección de un alumno durante una
carrera). En cualquier caso, durante este curso no se pide que seas capaz todavía de
hacer este tipo de optimizaciones más propio de una asignatura de Administración
de Bases de Datos.
Los literales cadena se representan encerrados en comillas simples, por ejemplo: 'Pepe', 'Av. Cantabria', o la
cadena vacía ''.
• Tipos Numéricos: Los tipos numéricos pueden ser de dos tipos: enteros y reales1. Los enteros se pueden
representar de varias formas:
• INTEGER o SMALLINT, donde INTEGER tendrá en general mayor rango que SMALLINT. El rango
en concreto que tenga cada uno de estos tipos estará en función del SGBD y de la máquina sobre la
que éste trabaje. Podríamos asumir en general, que un integer se representa con 2 bytes, y un smallint,
con 1 byte, con lo que los rangos son los que surjan de aplicar el correspondiente complemento a dos.
• NUMERIC ( n ) o DECIMAL(n), donde n es un entero mayor que cero que representa el número
máximo de cifras del número.
Los literales enteros se representan tal cual, sin comillas. Si son negativos llevan el signo menos delante, y
sino podrían llevar el signo mas opcionalmente (por ejemplo: 45, -45, +45).
En cuanto a los reales, podemos especificar:
• NUMERIC ( n, m) o equivalentemente DECIMAL ( n, m), donde n es un entero mayor que cero, y m
otro entero mayor o igual que cero. n representa el número de dígitos totales que puede albergar como
máximo, mientras que m representa cuántos de esos dígitos se corresponden con la parte decimal. Por

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

ello, da lo mismo decir NUMERIC ( 3, 0) que NUMERIC (3) directamente.


Por ejemplo, con NUMERIC ( 8, 2 ) es posible representar el número 123456.78, pues tiene 8 cifras
en total, de las cuales dos son decimales. En NUMERIC ( 8, 2) también cabe el número negativo
-123456.78.
NUMERIC y DECIMAL no se almacenan en coma flotante, es decir no se almacenan internamente
como una potencia multiplicada por una mantisa. Sino que se almacenan con esos n dígitos de
precisión.
Comentario: La diferencia entre NUMERIC y DECIMAL no es apreciable
la mayoría de las veces. Con NUMERIC el SGBD guarda internamente un
número con exactamente los n dígitos de precisión especificados, mientras
que DECIMAL puede guardar internamente el número, con una precisión aún
mayor de la especificada, y cuando lo vamos a utilizar lo redondea. Ese
redondeo puede ser desaconsejable, por ejemplo cuando se trata de
cantidades de dinero. Por tanto, lo importante es no utilizar DECIMAL
cuando no queramos problemas con los redondeos.
Los literales DECIMAL y NUMERIC se representan igual que los enteros, salvo que ahora pueden
llevar punto decimal, que se representa con el “.”. Por ejemplo -50.03 o +50.03 o 50.03.
• REAL, DOUBLE PRECISION y FLOAT(p): permiten almacenar números reales almacenados en
coma flotante. La precisión de REAL y DOUBLE no la marca el estándar, sino que la elige el
fabricante. Lo único que dice el estándar es que la precisión de REAL ha de ser menos que la de
DOUBLE. En BDs de gestión normalmente no utilizaremos ninguno de estos tipos, pues son más
apropiados para datos científicos y de ingeniería.
Los literales flotante, se representan por <mantisa opcionalmente con signo> y <exponente
opcionalmente con signo>, por ejemplo: -12.03 e 10, 23 e +14, 23.00 e 14, etc.
Comentario: FLOAT(p), donde p es la precisión, te permite especificar la
precisión. Internamente, el sistema probablemente lo almacene como REAL
si en ese SGBD FLOAT(p) cabe en un REAL, y sino lo almacenará en un
DOUBLE. FLOAT tiene sentido para hacer la BD portable entre SGBDs, sin
preocuparse de cual sea la precisión asignada a REALs y DOUBLEs en el
SGBD destino.
• Tipos fecha y hora: Hay tres tipos fundamentales: DATE, TIME y TIMESTAMP. DATE representa una
fecha cualquiera, TIME una hora con precisión de segundos.
Comentario: Si quieres que TIME tenga precisión de fracciones de segundo,
hay que especificar TIME(p). Por ejemplo, si queremos décimas sería
TIME(1), centésimas TIME(2), etc. Como mínimo, un SGBD estándar
debería soportar TIME(6).
TIMESTAMP es un tipo que aglutina la fecha y la hora con precisión de millonésima de segundo,
permitiendo así señalar de manera exacta un momento en el que ha transcurrido un suceso determinado.
Comentario: Se puede declarar TIMESTAMP(p) para especificar
precisiones mayores, cada SGBD puede soportar o no una precisión mayor o
menor.

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'

Comentario: o bien (formato Estados Unidos): DATE '04-08-2005', o bien


(formato japonés): DATE '2005-04-08'. Dependerá de cómo esté configurada
la base de datos. Normalmente, el instalador de la base de datos pregunta al
sistema operativo por la configuración regional, por lo que no deberías de
tener que hacer nada para ver y manipular las fechas directamente en formato
europeo.
• Para especificar el literal TIME correspondiente a las 8 y media de la tarde haríamos:

TIME '08:30:00 PM'

o por ejemplo también:

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:

TIMESTAMP '08-04-05 08:30:00 PM'

la fecha podría también especificarse en otros formatos.


Importante: Actualmente muchos SGBDs son capaces de deducir por el contexto del comando SQL, cuando una
cadena de caracteres debiera de ser una fecha, hora o fecha-hora, haciendo entonces la conversión de tipos
correspondiente. Pero esa conversión no funciona en todos los SGBDs porque no es estándar SQL.
• Booleanos: En SQL-92 no hay booleanos propiamente. No obstante en versiones posteriores del estándar si
se ha definido el tipo BOOLEAN. Los literales booleanos pueden tomar los valores true o false.

2.2.2 El valor NULL


NULL es un valor especial que puede tomar un campo de una tabla cualquiera que sea el tipo del mismo. Se dice que
el nulo es un valor compatible con cualquier tipo. Es decir un campo numérico puede tomar el valor nulo, y una fecha
también etc.
Los nulos pueden significar muchas cosas (se dice que tienen una semántica sobrecargada). Por ejemplo:
1. El nulo puede indicar que desconozco el valor. Por ejemplo, podemos poner a nulo la fecha de alta en la
empresa si la desconocemos o no la recordamos.
2. Podría ser que indicase que el valor es conocido, pero inaplicable al campo. Por ejemplo, en la tabla de
vehículos el campo color podría tomar el valor nulo si el coche fuese de múltiples colores.
3. Podría ser que el valor no existe. Por ejemplo, el campo DNI de un niño.
Por tanto, debemos de tomar el nulo como una marca especial que representa información desconocida, inaplicable,
inexistente, no válida, no proporcionada, indefinida, etc. Esta cantidad de significados que puede tener un nulo, es en
sí un problema, pues cuando encontremos un nulo, no sabremos en cuál de estos casos estaremos.
Algunos novatos de las bases de datos confunden el valor NULL con otros valores. Un nulo no es la cadena vacía '',
ni el cero numérico, ni el falso booleano.

Bases de Datos 10
Grado en Ingeniería Informática

Comentario: Antiguamente las bases de datos y las aplicaciones que procesaban


datos contra ficheros carecían de nulos. ¿Qué es lo que se hacía para resolver el
problema?: Cada programador lo resolvía de una manera distinta, poniendo una
marca especial conocida por el, pero no necesariamente conocida y/o utilizada por
los demás.
Por ejemplo, un programador podría decidir que la fecha de alta en la empresa
tomara un valor “D” cuando fuese desconocida, o que el DNI tomase el valor “N”
cuando fuese de un niño, o que el color del coche tomara el valor “VARIOS” cuando
fuese multicolor.
La ventaja es que cada programador podía acotar a su manera los múltiples
significados de estas marcas, de manera que cada una podía significar un algo más
concreto, y por tanto nos proveyese más información que una única marca genérica
como es el nulo. Pero, sin embargo, esto arrastra el siguiente problema: cada
programador tenía sus propias marcas, por lo que en la misma empresa, la misma
marca utilizada por programas distintos podría significar cosas diferentes, lo que a
su vez:
1. Dificulta la integración de las distintas bases de datos y ficheros de la empresa.
2. Dificulta el propio mantenimiento y evolución de las bases de datos (añadir un nuevo
campo, cambiar uno existente etc...).
Por ello, es útil unificar y estandarizar todos estos casos con una única marca, como
es el nulo. Esta ventaja se hace más patente cuando tenemos que pensar en qué va a
pasar cuando alguno de estos datos nulo vaya intervenir como operando en alguna
operación. Por ejemplo: cómo se va a comportar un programa que haga la media de
los sueldos cuando se encuentre que un sueldo es desconocido, o quizás otro
inaplicable porque se trata de un trabajador por cuenta propia etc. Sería interesante
que este comportamiento fuese por defecto siempre el mismo, para que sea
independiente del programador de turno y del SGBD de turno. Esta es la ventaja que
aporta el NULL de SQL.
Ejercicio 2:
Crea un script que cree una tabla de facturas con los siguientes campos
1. Número de factura que es un entero
2. Fecha de la factura.
3. Razón social del cliente que es una cadena de longitud 40 como máximo
4. Importe que tiene 8 dígitos antes de la coma y 2 dígitos detrás de la coma
Llama al script resultante PR1-05.sql

2.2.3 Sintaxis de la Definición de Columna


Como ya hemos adelantado, en la declaración del CREATE TABLE hay una lista de definiciones de columna
separadas por comas, siguiendo la siguiente sintaxis:
1. Primero se pone obligatoriamente el nombre del campo.

Bases de Datos 11
Grado en Ingeniería Informática

2. A continuación se pone obligatoriamente el tipo de datos del campo.


3. A continuación, opcionalmente, se puede especificar una clausula DEFAULT que sirve para establecer un
valor por defecto para ese campo. Por ejemplo, podemos querer que el campo saldo de la tabla de clientes
tenga el valor por defecto cero. Esto permitirá que cuando demos de alta un nuevo cliente y no digamos qué
saldo tiene, la máquina directamente le asigne el saldo cero. Por ejemplo:

saldo NUMERIC ( 8, 2 ) DEFAULT 0,

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:

Apellido2 CHAR ( 8 ) DEFAULT '',


FechaIngreso DATE DEFAULT DATE '01-01-2000',

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:

últimaSalida DATE DEFAULT CURRENT_DATE,

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í:

IdAlumno INTEGER PRIMARY KEY CHECK(IdAlumno>0),

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:

IdAlumno INTEGER CHECK(IdAlumno>0) PRIMARY KEY,

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:

saldo NUMERIC( 8, 2) DEFAULT 0 NOT NULL


CHECK(saldo>=0),

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.

2.2.4 Restricciones de Columna o de Campo


Una restricción de columna 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.
Las restricciones de columna son cuatro:
• NOT NULL: Sirve para especificar que esa columna nunca puede tomar un valor nulo, o lo que es lo

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é:

númeroHorasExtra SMALLINT CHECK( númeroHorasExtra > 0),

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

CHECK ( nombreDelCampo comparador comparando )

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

entrada TIMESTAMP CHECK( entrada >= CURRENT_TIMESTAMP),


2 Ya veremos más adelante como especificar claves primarias compuestas en SQL.
3 Ya veremos más adelante como especificar claves candidatas no primarias compuestas en SQL.

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:

hrsExtra INTEGER CHECK (hrsExtra>0),


hrsContratadas INTEGER CHECK( hrsContratadas < 100*30),

Es posible complicar las restricciones CHECK con AND OR y paréntesis, por ejemplo

hrsContratadas INTEGER CHECK(


hrsContratadas < 100
AND hrsContratadas >= 0),

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.

2.2.5 Nombrar las Restricciones


Es posible dar un nombre identificativo a las restricciones. Esto tiene principalmente dos ventajas:
1. Aunque, no es materia de este texto, las restricciones se pueden eliminar y modificar. No es posible decir
quiero eliminar o modificar esta u otra restricción si no tengo un nombre mediante el cual pueda
referenciarla.
2. Cuando al hacer una manipulación de datos ( altas, bajas o modificaciones) se intente violar una restricción,
el sistema no lo permitirá, abortando la operación y lanzando un mensaje informativo de por qué lo ha
abortado. El mensaje típicamente dirá “se ha intentado violar la restricción X”. Pues bien, para que esa X
tenga un valor que sea significativo para nosotros deberíamos de haber dado un nombre a la restricción.
No creamos que si no damos nombre a una restricción esta queda sin nombre. Normalmente, lo que ocurrirá es que el
sistema elegirá un nombre por nosotros, y claro está ese nombre podría ser poco descriptivo y quizás tenga un aspecto
de número de serie difícil de asociar mentalmente con nada.

Bases de Datos 14
Grado en Ingeniería Informática

CONSTRAINT nombre_constraint

NOT NULL
(columna)
UNIQUE

PRIMARY KEY (columnas)

FOREIGN KEY (columnas)

REFERENCES tabla

(columnas) ON DELETE CASCADE


CHECK (condición)
Figura 1: Diagrama sintáctico de railes típico de una restricción SQL.

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:

DNI CHAR(8) CONSTRAINT PK_Alumno PRIMARY KEY,

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.

2.2.6 Declaraciones de Restricciones de Tabla o Fuera de Línea


Hasta ahora hemos declarado las restricciones en la misma declaración del campo, este tipo de declaración es la más
habitual, y la llamaremos declaración en línea, o bien diremos que la restricción es de campo.
Como ya sospechábamos este tipo de declaración es insuficiente en algunos casos. Por ejemplo, supongamos que
tenemos una tabla de asignaturas con una clave primaria compuesta, formada por el IdTitulación y el IdAsignatura, y
supongamos que intentamos declararlo de la siguiente manera:

CREATE TABLE Asignaturas(


IdTitulacion SMALLINT PRIMARY KEY,
IdAsignatura INTEGER PRIMARY KEY,
Nombre CHAR(20) NOT NULL,
nCreditos SMALLINT NOT NULL CHECK (nCreditos >0)
);

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í:

CREATE TABLE Asignaturas(


IdTitulacion SMALLINT,
IdAsignatura INTEGER,
Nombre CHAR(20) NOT NULL,
nCreditos SMALLINT NOT NULL CHECK (nCreditos >0),
PRIMARY KEY( IdTitulacion, IdAsignatura)
);

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:

4 DEFAULT no se puede declarar fuera de línea porque no es una restricción.

Bases de Datos 16
Grado en Ingeniería Informática

CREATE TABLE Asignaturas(


IdTitulacion SMALLINT,
IdAsignatura INTEGER,
Nombre CHAR(20) NOT NULL,
nCreditos SMALLINT NOT NULL CHECK (nCreditos >0),
PRIMARY KEY( IdTitulacion, IdAsignatura),
UNIQUE(Nombre)
);

Cuando así sea:


1. Pueden ir declaradas en cualquier orden, por ejemplo podíamos haber declarado el UNIQUE antes del
PRIMARY KEY. En esto las declaraciones fuera de línea son iguales que las en línea.
2. Cada restricción va separada de la siguiente por una coma. Fíjate que al final de la PRIMARY KEY hay una
coma. En esto las restricciones fuera de línea son distintas a las en línea, que se separan por blancos,
tabuladores y/o retornos de carro.
Observa el UNIQUE, sólo afecta a un campo, podía haberse declarado entonces en línea. La conclusión es que todo
lo que se puede declarar en línea (salvo NOT NULL) se puede declarar también fuera de línea, pero atención: lo
contrario no es cierto; por ejemplo una clave compuesta sólo se puede declarar fuera de línea.
Las restricciones fuera de línea pueden optativamente también llevar un nombre, como vemos en el siguiente
ejemplo:

CREATE TABLE Asignaturas(


IdTitulacion SMALLINT,
IdAsignatura INTEGER,
Nombre CHAR(20) NOT NULL,
nCreditos SMALLINT NOT NULL CHECK (nCreditos >0),
CONSTRAINT PK_Asignaturas
PRIMARY KEY( IdTitulacion, IdAsignatura),
CONSTRAINT UNQ_Nombre_Asignaturas UNIQUE(Nombre)
);

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:

saldo NUMBER(6,0) CONSTRAINT NN_saldo NOT NULL,

• 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:

CREATE TABLE PROBLEMA(


Ciudad CHAR(13) NOT NULL,
FechaMuestra DATE,
Mediodía NUMERIC( 3, 1),
Medianoche NUMERIC( 3, 1),
Precipitación NUMERIC( 3, 1),
UNIQUE (Ciudad, FechaMuestra) );

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:

CREATE TABLE PROBLEMA(


Ciudad CHAR(13),
FechaMuestra DATE NOT NULL,
Mediodía NUMERIC( 3, 1),
Medianoche NUMERIC( 3, 1),
Precipitación NUMERIC( 3, 1),
PRIMARY KEY (Ciudad, FechaMuestra) );

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:

Campo1 INTEGER CHECK (Campo1>Campo2)

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

2.3. El Comando INSERT


El comando INSERT permite dar de alta nuevas filas en una tabla. INSERT tiene dos sintaxis, a saber: Inserción de
literales e inserción mediante consulta. Esta última se verá más adelante en la sección 2.7..
La inserción de literales permite insertar una única fila dando valores (literales) a los campos que deseemos. Su
sintaxis es:

INSERT INTO <nombre de tabla> [( <lista de


columnas>)]
VALUES (<lista de valores>);

Por ejemplo, supongamos una tabla de oficinas con los campos objetivo, ciudad y cod:

INSERT INTO oficinas ( objetivo, ciudad, cod)


VALUES ( 2000000, 'Valladolid', 8);

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:

INSERT INTO oficinas ( cod, ciudad)


VALUES ( 11, 'Cadiz');

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:

CREATE TABLE Oficinas (


objetivo numeric(7), ciudad CHAR(20),
cod INTEGER );

Podríamos hacer un INSERT así:

INSERT INTO oficinas VALUES ( 1000000, 'Burgos', 9);

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:

CREATE TABLE Precipitaciones (


Ciudad CHAR(13) NOT NULL,
FechaMuestra DATE NOT NULL,
Mediodía NUMERIC( 3, 1),
Medianoche NUMERIC( 3, 1),
Precipitación NUMERIC( 3, 1)
);

Supongamos que lanzamos el siguiente comando:

INSERT INTO Precipitaciones


VALUES ( 'Soria', '23-09-1993',
92.85, 79.6, 1.00003);

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

INSERT INTO Precipitaciones


VALUES ( 'Soria', '23-09-1993',
101.44, 79.6, 1.00003);

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:

INSERT INTO Precipitaciones (Ciudad)


VALUES ( 'Modúbar de la Emparedada');

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:

INSERT INTO oficinas VALUES ( 1000000, 'Burgos', 9),


( 2500000, 'Valladolid', 10),
( 50000, 'Soria', 11);

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?

2.4. La SELECT Básica


Nota: Casi todas las consultas de esta sección están en PR2-02.sql
SELECT es el comando más importante de SQL y Sirve para consultar la base de datos, es muy versátil, permitiendo
hacer de forma declarativa cualquier consulta que imaginemos. Sin embargo, determinadas consultas pueden llegar a
ser complicadas de especificar declarativamente. Por ello, el estudio de la SELECT necesita tiempo y mucha práctica.
Empezaremos en este tema con una descripción básica de la SELECT. Su sintaxis sería la siguiente:

SELECT [DISTINCT|ALL] <lista de ítemes


seleccionados>
FROM <lista de tablas>
[WHERE <Condición de Búsqueda>]
[ORDER BY <lista de expresiones de ordenación>];

Figura 2: Especificación BNF del comando SELECT.

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.

Figura 3: Diagrama Sintáctico de Raíles del comando SELECT.


Como ya sabíamos del CREATE TABLE, un comando SQL puede fraccionarse en tantas líneas como queramos,
podemos incluso ponerlo todo en una única línea. Por lo tanto, el número de líneas de una SELECT no es más que
una cuestión de estilo, si bien lo habitual es que cada cláusula ocupe al menos una línea, simplemente por una
cuestión de claridad.
Empezaremos por las cláusulas obligatorias. La cláusula FROM tiene como modificador obligatorio la lista de tablas
que van a intervenir en la consulta. En este tema sólo haremos consultas en las que interviene una única tabla, luego
la lista de tablas se limita a dar el nombre de la tabla que vamos a consultar.
En la cláusula SELECT tenemos que especificar los campos de la tabla que vamos a consultar. Lo más sencillo es que
esa lista de campos se especifique con “*”, que significa todos los campos.

7 Por eso están entre corchetes en su especificación sintáctica BNF.

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;

Figura 4: Ejemplo de SELECT * FROM.

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

Figura 5: Ejemplo de SELECT con lista de Campos.

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

opción por defecto. Así, daría lo mismo poner:

SELECT Altura FROM Alumnos;

que

SELECT ALL Altura from Alumnos;

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:

SELECT DISTINCT Altura from Alumnos;

el resultado hubiera sido:

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:

SELECT Altura, Peso FROM Alumnos;

o bien

SELECT ALL Altura, Peso FROM Alumnos;

Nos hubiera devuelto todos los valores de las columnas, tal cual. Pero para la tabla de la Figura 5:

SELECT DISTINCT Altura, Peso FROM Alumnos;

Nos hubiera devuelto:

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:

SELECT DISTINCT nombre, altura


FROM alumnos;

Tarda más en ejecutarse que:

SELECT nombre, altura


FROM alumnos;

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:

SELECT DISTINCT * FROM unaTabla;

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.

SELECT nombre,peso/(altura*altura), altura/0.3048,


peso/0.4536
FROM alumnos;

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'.

8 Aunque seguramente no lo devolverían en el mismo orden.

Bases de Datos 26
Grado en Ingeniería Informática

SELECT nombre, round(peso/(altura*altura),2),


round(altura/0.3048,2)||' pies',
round(peso/0.4536,2)||' libras'
FROM alumnos;

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:

SELECT 'Hola', nombre FROM alumnos;

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:

SELECT 'Hola' FROM alumnos;

Que devolvería tantas filas como alumnos hubiese, pero todas las filas serían iguales, incluyendo únicamente cada
una de ellas la palabra 'Hola'.

2.4.1 La Clausula WHERE


Usualmente no queremos que se nos muestren todas las filas de una tabla, sino sólo aquellas que cumplan una
determinada condición, para ello utilizaremos la cláusula opcional WHERE.
El modificador de la cláusula WHERE es un predicado lógico, el SGBD devolverá las filas de la tabla para las cuales
el predicado lógico tome el valor verdadero. Por ejemplo, con la última versión de la tabla de alumnos podríamos
hacer:

SELECT Altura, Peso


FROM Alumnos
WHERE peso=67;

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:

9 Ejemplo tomado de [Celko 2005].

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:

SELECT nombre FROM alumnos


WHERE (altura-1)*100>peso;

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

Devolviendo en ambos casos Pepe, Juan y Luis. Sin embargo:

SELECT Nombre
FROM Alumnos
WHERE peso=67
AND (altura=1.70
OR peso>80);

sólo devolvería Pepe. Otro ejemplo, esta vez con el NOT:

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';

2.4.2 Ordenación de la Consulta


El orden del resultado de una consulta en principio no quiere decir nada. Podríamos pensar equivocadamente que si
Juan nos es devuelto antes que Pepe significa que la fila con los datos de Juan fue introducida antes en la base de
datos. En general será puramente casual que una fila se muestre antes que la otra. Podemos repetir al cabo de un
tiempo la misma consulta, y obtener las filas en un orden distinto. En muchos casos este “caos” se debe a que al
comenzar a ejecutar la consulta coincidirá que haya determinados bloques de disco en memoria, y otras veces no. Si
por ejemplo, la fila de Pepe está en ese momento en memoria porque se utilizó en una consulta reciente, y la de 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;

Nos devolvería quizás:

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;

En cuyo caso el resultado sería Pepe, Luis, Ana en ese orden.


En todos los ejemplo vistos el orden ha sido ascendente: primero hemos facilitado a los menos altos y luego a los más
altos; primero a los menos pesados y luego a los más pesados. Sin embargo, es posible invertir los órdenes con el
modificador DESC (descending o descendente). Por ejemplo:

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

Devolvería Ana, Luis y Pepe.

SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura, peso DESC;

Devolvería Luis, Pepe y Ana.


Además del modificador DESC existe el ASC (ascending o ascendente) que hace todo lo contrario: es decir ordenar
por orden descendente, que es precisamente lo que se hace si no ponemos ni ASC ni DESC. Por lo tanto, casi nadie
utiliza el ASC. En ese sentido, la consulta anterior es equivalente a:

SELECT Nombre
FROM Alumnos
WHERE Nombre <>'Juan'
ORDER BY altura ASC, peso DESC;

Podemos especificar tantos criterios de ordenación como queramos, por ejemplo:

SELECT Nombre
FROM VotantesUE
ORDER BY país, región, provincia, población,
CP, Edad DESC;

Los criterios de ordenación podrían ser expresiones, por ejemplo:

SELECT Nombre FROM Alumnos


WHERE Nombre <>'Juan'
ORDER BY peso/(altura*altura) 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.

2.5. Eliminación de filas con DELETE


Nota: Casi todas las consultas de esta sección están en PR2-05.sql
El comando DELETE permite eliminar filas de una tabla. Su sintaxis es:

DELETE FROM <nombre tabla> [WHERE <condición>];

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:

DELETE FROM alumnos WHERE peso > 70;

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:

DELETE FROM alumnos;

borraría todas las filas de la tabla de alumnos.

2.6. Modificaciones de valores con UPDATE


Nota: Casi todas las consultas de esta sección están en PR2-05.sql
UPDATE permite modificar o asignar valores de uno o varios campos para un conjunto de filas que verifican una
condición WHERE. Su sintaxis es:

UPDATE <nombre de tabla>


SET <nombre de columna> = <expresión>
[, <nombre de columna> = <expresión>...]
[WHERE <condición>];

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';

haría que el peso de Pepe se incrementase un 20%.


Como en el caso del DELETE, la cláusula WHERE es optativa, y en caso de omitirla la actualización se extendería a
todas las filas de la tabla. Por ejemplo:

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;

Ojo, observa que al ejecutar secuencialmente:

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.

2.7. INSERT con sub-SELECT


Nota: Casi todas las consultas de esta sección están en PR2-05.sql
En esta modalidad de INSERT se adjunta una SELECT, y las filas que devuelva dicha SELECT serán las que se
inserten. Sirve por tanto, para copiar filas de unas tablas a otra. Por ejemplo:

INSERT INTO altos (nombre, pies)


SELECT nombre, altura/0.3048
FROM alumnos
WHERE altura > 1.70;

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.

2.8. CREATE TABLE AS SELECT


El comando CREATE TABLE visto en la sección 2.2. tiene una sintaxis alternativa como la del siguiente ejemplo:

Bases de Datos 34
Grado en Ingeniería Informática

CREATE TABLE altos ( nombre, pies ) AS


SELECT nombre, altura/0.3048
FROM alumnos
WHERE altura > 1.70;

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:

CREATE TABLE altos ( nombre char(10) primary key,


pies numeric(3,2));

INSERT INTO altos


SELECT nombre, altura/0.3048
FROM alumnos
WHERE altura > 1.70;

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:

CREATE TABLE altos AS


SELECT nombre, altura/0.3048
FROM alumnos
WHERE altura > 1.70;

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.

3. CREATE VIEW y DROP VIEW


Una vista (VIEW) es una consulta SELECT la cual se comporta como una tabla. No es una tabla porque no tiene filas
propias, las toma prestadas del resultado de la consulta, pero podríamos (en teoría) hacer con una vista las mismas
operaciones que con una tabla.

Bases de Datos 35
Grado en Ingeniería Informática

Por ejemplo:

CREATE VIEW altos ( nombre, pies ) AS


SELECT nombre, altura/0.3048
FROM alumnos WHERE altura > 1.70;

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:

SELECT * FROM altos;

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í:

CREATE VIEW altos AS


SELECT nombre, altura/0.3048
FROM alumnos WHERE altura > 1.70;

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:

DROP VIEW altos;

SQL no permite que borremos la tabla en la que se basa una vista si no borramos la vista primero. Por tanto, para
hacer

DROP TABLE alumnos;

Es necesario borrar la vista primero.


Una vista nos sirve para:
1. Tener una tabla en la que no están determinadas filas y/o columnas, de manera que por cuestiones de
confidencialidad, puede haber usuarios que no tengan privilegios para consultar la tabla, porque tiene
demasiada información, pero si puedan consultar la vista.
2. Hacer las funciones de esquema externo del modelo ANSI/X3/SPARC. Las vistas en principio admiten
operaciones INSERT, DELETE y UPDATE sobre las mismas, pero esta cuestión puede ser delicada, y por
ello está fuera del alcance de este curso. Podemos anticipar que no todas las vistas admiten DELETE, y que
sólo un subconjunto de de las que admiten DELETE admiten UPDATE, y de entre las que admiten
UPDATE, sólo un subconjunto de ellas admitirían INSERT. Por todo ello, la pretensión del modelo
ANSI/SPARC de utilizar las vistas como esquemas externos no ha sido muy exitosa en las bases de datos
SQL.

Bases de Datos 36
Grado en Ingeniería Informática

Comentario: Por ejemplo, si intentamos cambiar la altura con un UPDATE en la


vista del ejemplo daría error, porque la base de datos no es suficientemente “lista”
como para deducir la conversión de pies a centímetros. Existen mas situaciones
problemáticas. Por ejemplo, imagina que la tabla alumnos tuviera un campo DNI
que es PRIMARY KEY o simplemente es NOT NULL. Si hiciéramos un INSERT
sobre la vista no podríamos dar valor a ese campo obligatorio y nuevamente daría
error. Es más, en el caso de que DNI fuese clave primaria y nombre no lo fuese,
cuando hiciéramos un DELETE en la vista de los que se llamasen Juan, podríamos
tener nuevamente problemas si la vista se hubiese creado mediante SELECT
DISTINCT … ya que si dos alumnos se llamasen Juan y tuviesen la misma altura
generarían una única fila en la vista, pese a ser 2 filas de la tabla. Al intentar hacer
DELETE de la fila en la vista, el SGBD no sabría muy bien qué fila de la tabla
borrar, y también se quejaría.
Ejercicio 8:
Toma el fichero PR2-06.sql y haz lo que pide el enunciado en su interior. Graba el resultado en PR2-07.sql

4. Declaración de claves ajenas


En el Tema 1 se explicó que una clave ajena eran los campos que conformaban una clave primaria en otra tabla, y que
servía para relacionar los valores de ambas tablas, y para restringir que los campos de la clave ajena tomasen valores
que no estuvieran presentes en la clave primaria con la que se relaciona (i.e., restricción de integridad referencial). En
esta sección veremos la sintaxis SQL para declarar las claves ajenas.
Supongamos una tabla de estudios cinematográficos y otra de estrellas de cine 10. La tabla de estudios tiene como
clave primaria el nombre del estudio. Cada estrella pertenece en cada momento a un solo estudio. Las estrellas de
cine sólo pueden pertenecer a un estudio de cine, y un estudio de cine, puede tener en nómina a varias estrellas. Por
ello, añadimos a la tabla de estrellas un campo estudio que funcionará como clave ajena.
Cuando hay dos tablas relacionadas por una clave ajena se acostumbra a llamar tabla hija a la que tiene la clave
ajena, y tabla padre a la que no la tiene. En nuestro ejemplo, la tabla padre son los estudios, cada estudio “tiene
varios hijos”: sus estrellas.
La declaración de clave ajena se hace mediante FOREIGN KEY – REFERENCES , de manera que declaramos la
tabla de estrellas de la siguiente forma:

10 Ejemplo tomado de [Melton y Simon 1993].

Bases de Datos 37
Grado en Ingeniería Informática

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios,
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)

);

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

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2),
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2),
CONSTRAINT FK_estrella_estudio
FOREIGN KEY (numEstudio) REFERENCES estudios
);

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:

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios
ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)
);

O bien

Bases de Datos 39
Grado en Ingeniería Informática

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2),
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2),
CONSTRAINT FK_estrella_estudio
FOREIGN KEY (numEstudio) REFERENCES estudios
ON DELETE NO ACTION ON UPDATE NO ACTION
);

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:

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)
);

O bien

Bases de Datos 40
Grado en Ingeniería Informática

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios
ON DELETE CASCADE
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)
);

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:

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2),
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2),
CONSTRAINT FK_estrella_estudio
FOREIGN KEY (numEstudio) REFERENCES estudios
ON DELETE CASCADE
ON UPDATE NO ACTION
);

O de la misma forma, podríamos quitar el ON UPDATE:

Bases de Datos 41
Grado en Ingeniería Informática

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2),
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2),
CONSTRAINT FK_estrella_estudio
FOREIGN KEY (numEstudio) REFERENCES estudios
ON DELETE CASCADE
);

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:

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios
ON DELETE NO ACTION
ON UPDATE CASCADE,
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)
);

Ahora podríamos quitar el ON DELETE, por ser NO ACTION, y quedaría:

Bases de Datos 42
Grado en Ingeniería Informática

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios
ON UPDATE CASCADE,
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)
);

Podríamos haber declarado que ambos comportamientos (delete y update) fuesen en cascada:

CREATE TABLE estrellas (


nombre_artistico CHAR(30),
nombre CHAR(35),
ape1 CHAR(35),
ape2 CHAR(35),
numEstudio CHAR(2)
CONSTRAINT FK_estrella_estudio REFERENCES estudios
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT PK_estrellas
PRIMARY KEY ( nombre, ape1, ape2)
);

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

CREATE TABLE Peliculas (


titulo CHAR(40) PRIMARY KEY,
nombre_prota CHAR(35),
ape1_prota CHAR(35),
ape2_prota CHAR(35),
FOREIGN KEY
( nombre_prota, ape1_prota, ape2_prota)
REFERENCES estrellas);

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:

FOREIGN KEY ( nombre_prota, ape1_prota, ape2_prota)

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:

FOREIGN KEY (ape1_prota, ape2_prota, nombre_prota)


REFERENCES estrellas

como en estrellas hemos declarado:

PRIMARY KEY ( nombre, ape1, ape2)

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:

DROP TABLE estudios CASCADE;

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

Alumnos ( IdAlumno, DNI, Nombre, FechaNacimiento, dirección)


PK UNQ

FK FK
Notas ( IdAlumno, IdAsignatura, IdTitulación, Nota )
PK

Asignaturas ( IdAsignatura, IdTitulación, Nombre, Curso, NumCréditos )


PK

Profesores ( IdProfe, Nombre, Despacho, Tfno, IdAsignatura, IdTitulación)


PK FK
Figura 6: Esquema relacional del Ejercicio 6.

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)

[Elmasri y Navathe 2007] Elmasri, Ramez y Navathe, Shamkant B. Fundamentos de Sistemas


de Bases de Datos 5ª ed. Pearson, 2007
(Disponible en UBUvirtual: http://0-www.ingebook.com.ubucat.ubu.es/ib/NPcd/IB_BooksVis?
cod_primaria=1000187&codigo_libro=2886)

[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

[Silberschatz et. al 2006] Silberschatz, Abraham, Korth, Henry F. y Sudarshan, S.


Fundamentos de Bases de Datos 5ªEd. McGraw-Hill, 2006.
(Disponible en UBUvirtual: http://0-www.ingebook.com.ubucat.ubu.es/ib/NPcd/IB_BooksVis?
cod_primaria=1000187&codigo_libro=4356 ).
Bibliografía comentada:
Quizás la referencia que más se extiende en los contenidos de este tema y con mayor profundidad es [Melton y Simon
1993] en sus capítulos del 2 al 4 inclusive, lo cual no es extraño pues el propio Jim Melton fue el editor del estándar
SQL ISO de 1992.
En cuanto a la bibliografía en línea de la que dispone el alumno, cualquiera de los libros de cabecera trata con
suficiente amplitud los contenidos revisados en el presente capítulo, así:
• En [Connolly y Begg 2005] la SELECT básica aparece en la sección 5.3.1, los comandos INSERT-
DELETE-UPDATE en la sección 5.3.10, el comando CREATE TABLE y las restricciones en las secciones
6.1, 6.2, 6.3; las vistas en la 6.4
• En [Silberschatz et. al 2006] la sección 3.2 explica la creación de tablas en SQL a nivel básico, las
restricciones se cuentan en la sección 4.2, la sección 3.3. cuenta la SELECT básica, la 3.6 los valores nulos,
la 3.9 las vistas y la 3.10 los comandos INSERT-DELETE-UPDATE.
• En [Elmasri y Navathe 2007] la sección 8.1 trata el CREATE TABLE, la 8.2 las restricciones, la 8.3 el
DROP TABLE, la 8.4.1 a 8.4.3 la SELECT básica, la 8.6 los comandos INSERT-DELETE-UPDATE, la 8.8
las vistas.

VII. Material complementario

La gramática estándar SQL puede encontrarse en los siguientes enlaces:


1. http://savage.net.au/SQL/ en el que la gramática de las versiones estándares SQL-92, 99 y 2003 aparecen en
formato BNF. Por tanto, lo interesante de esta referencia es que abarca 3 versiones del estándar.
2. http://cui.unige.ch/db-research/Enseignement/analyseinfo/SQL92/BNFindex.html incluye sólo el estándar
92, pero lo hace tanto utilizando BNF como diagramas de raíles, estos último suelen ser más atractivos a los
alumnos.
DB5 SQL. Videos 1 (Introducción to SQL), 2 (Basic Select Satement) y 9 (Data modification
statements) Prof. Jennifer Widom, Standford University
https://lagunita.stanford.edu/courses/DB/SQL/SelfPaced/courseware/ch-sql/
El vídeo 9 sólo ver la primera mitad. La segunda mitad es muy interesante, pero no lo vas
a entender hasta que no veamos las subconsultas en el tema 5.

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

También podría gustarte