Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Apuntes ICA0 M02-UF2 - ICA0002-S02, ICA0002-S03 e ICA0002-S04
Apuntes ICA0 M02-UF2 - ICA0002-S02, ICA0002-S03 e ICA0002-S04
ICA0002-S02-C01
ICA0002-S2-C1-V1 La Selección
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102393)
La selección es la operación básica de toda base de datos, ya que con ella podemos obtener
información de la base de datos.
Ejemplo: en el siguiente esquema relacional, tenemos la tabla Equipo y la tabla Jugador. Los
jugadores se relacionan con los equipos con la PK o FK (dependiendo de la tabla que se mire)
nombre_equipo.
Cláusulas
SELECT → Define qué se quiere obtener; qué queremos que nos devuelva el sistema.
WHERE → Son las condiciones que queremos utilizar para filtrar lo que nos devuelve el sistema.
Página 1 de 113
De estas seis cláusulas, hay dos obligatorias cuando se escribe un SELECT: SELECT y FROM.
El sistema, según se ejecuta, no lo hace de la misma manera. Cuando se hace una selección, el
sistema primero comprueba la parte de FROM —es decir, dónde está la información—; luego le
aplica las condiciones utilizadas para filtrar lo que ha de devolver (WHERE); agrupa los resultados
como se le ha pedido (GROUP BY) —si es que se ha solicitado una agrupación—; seguidamente
aplica las condiciones de grupo (HAVING) —si es que hay condiciones de grupo—; ordena los
resultados (ORDER BY) y los muestra por pantalla —hace el SELECT—, mostrando lo que el
usuario desea.
Operadores
Operadores de comparación:
Página 2 de 113
Supongamos el siguiente esquema relacional:
• MENOR QUE (<): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea menor que (<) 1000000
• MAYOR QUE (>): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea mayor que (>) 1000000
• MAYOR O IGUAL QUE (>=): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea mayor o igual que (>=) 1000000
• MENOR O IGUAL QUE (<=): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea menor o igual que (<=) 1000000
También podemos comprobar que un atributo tiene un valor concreto. En este caso, se usa el
igual (=), del que hay dos tipos, para cifras y para ‘texto’.
• IGUAL QUE (=): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea igual que (=) 1000000
Página 3 de 113
• DIFERENTE QUE (<>): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea diferente a (<>) 1000000
Se utiliza en cadenas de texto; por ello, con el comparador LIKE siempre se utilizarán comillas
simples ‘ ’.
Con LIKE se pueden hacer comparaciones parciales en una cadena de texto. Por ejemplo,
comprobar que algo (como el nombre de los equipos de la tabla Equipo) empieza por un carácter
o por una serie de caracteres.
• Empieza por: LIKE ‘B%’; (en este caso, se comprueba que ese algo empieza por B.
Nótese que después de B se pone %, indicando que después de la B puede haber, o no,
uno o más caracteres).
• No empieza por: NOT LIKE ‘B%’; (en este caso, se comprueba que ese algo NO
empieza por B).
• Termina por: LIKE ‘%A’; (en este caso, se comprueba que ese algo termina con A).
• Contiene: LIKE ‘%A%’; (en este caso, se comprueba que ese algo contiene la letra A;
lo que significa que antes y después de la A puede haber o no caracteres).
• Tiene X letras (por ejemplo, 5): LIKE ‘_ _ _ _ _’; (con esto se comprueba el
número de caracteres que tiene un valor concreto de un atributo).
• EMPIEZA POR: Obtener el nombre de los equipos, de la tabla Equipo, cuyo nombre
empiece por B → LIKE ‘B%’;
Página 4 de 113
• NO EMPIEZA POR: Obtener el nombre de los equipos, de la tabla Equipo, cuyo nombre
NO empiece por B → NOT LIKE ‘B%’;
• TERMINA POR: Obtener el nombre de los equipos, de la tabla Equipo, cuyo nombre
termine por A → LIKE ‘%A’;
• TIENE 5 LETRAS: Obtener el nombre de los equipos, de la tabla Equipo, que tengan 5
caracteres. → LIKE ‘_ _ _ _ _’;
• TIENE AL MENOS DOS LETRAS (O MÁS): Obtener el nombre de los equipos, de la tabla
Equipo, que tengan 2 caracteres o más → LIKE ‘_ _ %’;
Página 5 de 113
Operador de comparación BETWEEN
• Comprobar que algo esté dentro del rango entre 1000000 y 2000000:
BETWEEN 1000000 AND 2000000;
• Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto esté dentro
del rango entre 1000000 y 2000000 → BETWEEN 1000000 AND 2000000;
Operadores lógicos
• Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto sea mayor
que 1000000 y (AND) cuyo nombre empiece por B → WHERE (para establecer las
condiciones a utilizar para filtrar lo que devuelve el sistema) presupuesto >
1000000 AND nombre_equipo LIKE ‘B%’;
Página 6 de 113
OR → Indica que se ha de cumplir una condición o la otra. Se pueden cumplir las dos, pero con
que se cumpla una de las dos es suficiente.
• Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto sea mayor
que 1000000 o (OR) cuyo nombre empiece por B → WHERE (para establecer las
condiciones a utilizar para filtrar lo que devuelve el sistema) presupuesto >
1000000 OR nombre_equipo LIKE ‘B%’;
Concatenación de operadores lógicos (ejemplo, concatenar tres AND dentro del WHERE)
Dentro del WHERE puede usarse más de un operador lógico para concatenar más de dos
comparaciones.
• Concatenación de AND (se mostrarán aquellos equipos que cumplan las tres
condiciones): Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto
sea mayor a 1000000 y (AND) que su nombre empiece por B y (AND) que el año de su
fundación sea anterior a 1900 → WHERE presupuesto > 1000000 AND
nombre_equipo LIKE ‘B%’ AND ano_fundacion < 1900;
• Combinación de AND y OR (se mostrarán aquellos equipos que cumplan las dos
primeras condiciones, o se mostrarán aquellos equipos que cumplan las dos últimas
condiciones): Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto
sea mayor a 1000000 (>) y (AND) que el año de fundación sea anterior/menor a 1900
(<), o (OR) que el presupuesto sea menor a 1000000 (<) y (AND) que el año de
fundación sea posterior/mayor a a 1900 (>) → WHERE (presupuesto >
1000000 AND ano_fundacion < 1900) OR (presupuesto < 1000000
AND ano_fundacion > 1900);
Página 7 de 113
ICA0002-S2-C1-V2 La Selección. Elementos Auxiliares y otros ejemplos
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102394)
Todos los ejemplos se basan en este esquema relacional, donde hay equipos y jugadores (por
cada equipo tenemos varios jugadores, los cuales se relacionan a través de la PK FK
nombre_equipo).
Elementos auxiliares
Alias (AS)
El alias (AS) lo que hace es que, al devolver el resultado, el atributo nombre_equipo se llama
nombre_del_equipo. No cambia nada dentro del modelo de base de datos; la base de datos
sigue igual, pero la respuesta se da con el nombre del alias.
También podemos usar el alias (AS) en el FROM. Se puede definir al lado de la tabla. Cuando se
pone el nombre de la tabla Equipo como e (equipo AS e) se está diciendo que a la tabla
Equipo se puede llamar e, lo que es muy útil para hacer referencia a atributos de una tabla
cuando se trabaja con más de una tabla por selección.
Página 8 de 113
En el ejemplo inferior, lo que se dice es que el nombre de equipo es de la tabla de Equipo
indicando e.nombre_equipo, ya que e es el alias de Equipo. Se hace lo mismo con el
presupuesto, indicando, tras el WHERE, e.presupuesto.
Referencias como la que se acaba de tratar pueden hacerse sin el alias, indicando directamente
el nombre de la tabla.
Esto es muy útil cuando se utilice más de una tabla para una selección, sobre todo para hacer
referencia a aquellos atributos que aparezcan en las dos o tres tablas que se cojan.
Dentro de una tabla, una columna a menudo contiene muchos valores duplicados, y en
ocasiones solamente se desea enumerar los valores distintos. O, dicho de otro modo, se quieren
enumerar los valores sin duplicidades.
En el siguiente ejemplo, se enumeran los valores de la columna apellido, de la tabla Jugador, SIN
repeticiones. Es decir, si hay dos o más García solo se muestra uno.
Página 9 de 113
Combinación de alias (AS) con DISTINCT (DISTINCT)
Mediante AS, la columna apellido, de la tabla jugador, aparece como apellidos, lo cual es más
limpio. Además, puesto que se combina con la función DISTINCT, no se mostrarán aquellos
apellidos repetidos.
Operador *
El operador * quiere decir «todos los atributos». Por tanto, SELECT * FROM equipo;
muestra todos los atributos de la tabla equipo (en este caso, nombre_equipo, presupuesto y
ano_fundacion), junto con todos sus valores.
Página 10 de 113
Otros ejemplos
Selecciones multiatributo
Los valores NULL conciernen a esos atributos que no tienen ningún valor; están vacíos. Se
pueden hacer consultas en base a esto.
NULL puede usarse para seleccionar a aquellos jugadores sin equipo. En este caso, lo que se
dice es que se muestren todos los atributos de la tabla jugador cuyo atributo nombre_equipo
sea NULL; esté vacío. Puede hacerse de dos maneras, con IS NULL o con = NULL.
NULL también puede utilizarse para seleccionar aquellos jugadores con equipo. En este caso,
lo que se dice es que se muestren los atributos de la tabla jugador cuyo atributo nombre_equipo
no sea NULL; es decir, que tenga un valor. Puede hacer de dos maneras, con IS NOT NULL o
con <> NULL
Página 11 de 113
Selecciones con operaciones matemáticas en el SELECT
Por ejemplo, pueden mostrarse los equipos y sus presupuestos sumando un millón extra a
dichos presupuestos:
La sintaxis también puede ser más elaborada, como SELECT atributo*(1-0.2) FROM
tabla;
Ejemplo: Mostrar los equipos y sus presupuestos con un millón extra en sus presupuestos:
Ejemplo: Mostrar los equipos con sus presupuestos aplicando un -20% para quitar los
impuestos (también se le aplican un alias AS):
Página 12 de 113
ICA0002-S2-C1-V3 La Selección. Funciones
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102395)
Todos los ejemplos se basan en la siguiente base de datos, compuesta por tres tablas: Alumno,
Estudia y Asignatura. Por tanto, varios alumnos estudian varias asignaturas.
Funciones de fecha
MySQL comes with the following data types for storing a date or a date/time value in the
database
MySQL viene con los siguientes tipos de datos para almacenar una fecha o un valor de
fecha/hora en la base de datos:
SQL Server comes with the following data types for storing a date or a date/time value in
the database
SQL Server dispone de los siguientes tipos de datos para almacenar una fecha o un valor de
fecha/hora en la base de datos
Página 13 de 113
NOW()
Puede utilizarse, por ejemplo, para seleccionar los nombres y apellidos de los alumnos con
fecha de nacimiento menor a la fecha actual.
CURRENT_DATE()
Puede utilizarse para seleccionar los nombres y apellidos de los alumnos con fecha de
nacimiento menor a la fecha actual. Solo compararemos con la fecha del día, sin tener en cuenta
las horas, los minutos y los segundos.
Página 14 de 113
YEAR(‘date’), YEAR(‘datetime’) o YEAR(atributo)
Las comillas simples ‘ ’ no se usan cuando YEAR() modifica los valores de un atributo
—YEAR(fecha_nacimiento)—
date | datetime Required. The date or datetime to extract the year from. Traducción:
YEAR(‘’) requiere la fecha (date) o fecha-hora (datetime) de la que
se extrae el año.
Página 15 de 113
Otro ejemplo: SELECT YEAR('1994/08/31') AS Year;
En el siguiente ejemplo, el sistema devuelve los DNI y el año en el que ha nacido cada uno de los
alumnos, puesto que en la selección se especifica que, de la tabla alumno, se muestre el atributo
DNI y el atributo fecha_nacimiento modificado con YEAR() —
YEAR(fecha_nacimiento)—.
En el siguiente ejemplo, el sistema devuelve los DNI de los alumnos nacidos antes de 1990,
puesto que en la selección se especifica que, de la tabla alumno, se muestre el atributo DNI,
mientras que la cláusula WHERE (que estipula las condiciones con las que se filtran los
resultados) establece que la fecha de nacimiento —obtenida modificando el atributo
fecha_nacimiento con YEAR(fecha_nacimiento)— sea menor a 1990.
Las comillas simples ‘ ’ no se usan cuando MONTH() modifica los valores de un atributo
—MONTH(fecha_nacimiento)—
La función MONTH() devuelve la parte del mes para una fecha especificada (un número del 1
al 12).
Página 16 de 113
La sentencia SQL SELECT MONTH('1994/08/31 09:08') AS Mes; devuelve el
resultado 8, estilizado con el título Mes gracias al alias (AS).
En el siguiente ejemplo, de la tabla alumno se muestran los valores de los atributos nombre y
apellido cuya fecha de nacimiento sea enero, puesto que la cláusula WHERE (que estipula las
condiciones con las que se filtran los resultados) establece que la fecha de nacimiento —
obtenida modificando el atributo fecha_nacimiento con MONTH(fecha_nacimiento)—
sea igual a 1.
En los dos casos siguientes, de la tabla alumno se muestran los DNI de aquellos cuya fecha de
nacimiento sea la del mes actual. Para ello, MONTH() se puede complementar con dos
funciones: NOW() —que devuelve un formato DATETIME, con la estructura YYYY-MM-DD
hh:mm:ss— o CURRENT_DATE() —que devuelve un formato DATE, con la estructura YYYY-
MM-DD—. Lo que ocurre es que se extrae el mes de la fecha actual, 1 si es enero, 2 si es febrero…
Página 17 de 113
La función DAY() devuelve el día del mes para una fecha determinada (un número del 1 al
31). Es igual a la función DAYOFMONTH().
En el siguiente caso, de la tabla alumno se muestran los nombres y apellidos de aquellos nacidos
el primer día del mes, estableciendo tras WHERE, que estipula las condiciones con las que se
filtran los resultados, que DAY(fecha_nacimiento) = 1. De este modo,
DAY(fecha_nacimiento) extrae los días, almacenados como valores en el atributo
fecha_nacimiento, y muestra aquellos que coincidan con 1; esto es, el primer día de cada mes.
Página 18 de 113
Funciones de texto
LENGTH()
De este modo, si deseo que se muestren los nombres de aquellas asignaturas que tengan 5
caracteres, puedo hacer lo siguiente:
Con LIKE:
Con LENGTH():
LENGTH() puede utilizarse con los operadores mayor que (>) y menor que (<).
Por ejemplo, si queremos mostrar los nombres de aquellas asignaturas que tengan más de 5
letras, puede hacerse:
CONCAT()
En el siguiente ejemplo, de la tabla alumno se muestra en una única columna los valores de los
atributos nombre, apellido y apellido2 coincidentes con el DNI 11111111A. O, dicho de otro
modo, se ha concatenado el nombres y apellidos del alumno cuyo DNI es 11111111A.
Página 19 de 113
Para añadir espacios al concatenar, estos deben incluirse expresamente entre comillas simples
‘ ’ (opcionalmente, se ha añadido un alias — AS— para simplificar la lectura).
Los ejemplos se basan en este esquema relacional, donde por un lado está la tabla Equipo y por
otro la tabla Jugador. Se relacionan entre sí con la PK o FK (dependiendo de la tabla que se mire)
nombre_equipo.
En la tabla Equipo hay dos equipos, Barcelona y Madrid, con su presupuesto y el año de su
fundación.
Página 20 de 113
En la tabla Jugador hay tres jugadores, con su DNI, nombre, apellidos, dorsal, posición y el
nombre del equipo en el que juegan.
Seleccionar el DNI de los jugadores (atributo que está en la tabla Jugador bajo la denominación
DNI) y el año de fundación de sus respectivos equipos (atributo que está en la tabla Equipo bajo
la denominación ano_fundacion) supone implicar a las dos tablas. Por ello, tras la cláusula FROM
han de especificarse ambas tablas, pero cuidado, porque hay que hacer algo más, que se
explica a continuación; de lo contrario el resultado será erróneo .
❌¡El resultado es incorrecto! ¿Por qué? Porque el sistema lo que hace es cruzar todos los
jugadores con todos los equipos. Es decir, relaciona todos jugadores del Barcelona con todos los
equipos, tanto el Barcelona como el Madrid; y relaciona todos los jugadores del Madrid con
todos los equipos, tanto el Barcelona como el Madrid. Consecuentemente, se produce una
incoherencia de datos, porque hay jugadores que relacionan con presupuestos de un equipo
que no es el suyo. ❌
¿Cómo se evita la incorrección? Cuando enfrentemos selecciones con más de una tabla, la
primera cosa que se ha de hacer, una vez que tras el FROM se hayan precisado ambas tablas, es
especificar claramente en la condición de WHERE cómo se relacionan las dos tablas. En este
caso, hay que detallar lo siguiente: equipo.nombre_equipo =
jugador.nombre_equipo; Con ello, se indica expresamente que el atributo
nombre_equipo de la tabla Equipo (la PK en el esquema relacional) debe coincidir con el atributo
nombre_equipo de la tabla Jugador (la FK en el esquema relacional). Es decir, que hay un atributo
Página 21 de 113
en Equipo y en Jugador que han de ser iguales para mostrar ese resultado como válido. Así, se
mostrarán los DNI de los jugadores del Barcelona y del Madrid con el presupuesto
correspondiente a su equipo.
La sentencia SQL anterior puede variar con los alias, pudiendo resultar más inteligible: se asigna
el alias e a la tabla Equipo y el alias j a la tabla Jugador; para ello, tras el FROM se escribe equipo
AS e, jugador AS j. Seguidamente, tras el WHERE se indica expresamente cómo se
relacionan las tablas. En este caso, hay que detallar e.nombre_equipo =
j.nombre_equipo;.
Como se desea mostrar información de solo una de las tablas relacionadas, hay un problema, y
es que con * no vale, puesto que si se pone SELECT * se mostrarán todos los atributos, tanto
de Equipo como de Jugador, y solo se quieren los atributos de Jugador.
Página 22 de 113
La solución es escribir, tras el SELECT, j.* (alias de Jugador) o jugador.*. De esta manera,
solo se muestran los atributos pertenecientes a Jugador —o a j, que es el alias de Jugador—.
En el caso de que quiera seleccionar todos los jugadores del Barcelona, no es necesario coger
dos tablas, puesto que en la tabla Jugador ya está el atributo nombre_equipo (es su FK). Así, en
la cláusula WHERE se puede igualar directamente el nombre_equipo de la tabla Jugador con
‘Barcelona’ —WHERE j.nombre_equipo = ‘Barcelona’—.
Página 23 de 113
Selecciones con 3 tablas
Los ejemplos se basan en este esquema relacional, donde por un lado está la tabla Alumno y por
otro la tabla Asignatura, relacionadas por medio de la tabla Estudia.
En este caso, se muestra el nombre y apellido de los alumnos utilizando el alias a —SELECT
a.nombre, a.apellido—, si bien en apellido no es necesario porque no hay ningún otro
atributo apellido; sin embargo, en el atributo nombre sí es necesario, puesto que el atributo
nombre está tanto en la tabla Alumno como en la tabla Asignatura, y lo que se quiere mostrar
es el atributo nombre de Alumno.
En FROM se selecciona la tabla Alumno y se aplica el alias a; la tabla Estudia y se aplica el alias e;
y la tabla Asignatura y se aplica el alias as —FROM alumno AS a, estudia AS e,
asignatura AS as—.
En WHERE se estipula que el DNI de la tabla Alumno (cuyo alias es a) sea igual al DNI de la tabla
Estudia (cuyo alias es e) —a.DNI = e.DNI— y (AND) que la id_asignatura de la tabla Estudia
(cuyo alias es e) sea igual al id_asignatura de la tabla Asignatura (cuyo alias es as) —
e.id_asignatura = as.id_asignatura—. Con estas dos igualaciones se relacionan
las tres tablas, Alumno, Estudia y Asignatura.
Seguidamente, se añade otro AND para especificar otra condición: que el valor del atributo
nombre de la tabla Asignatura sea igual a ‘Bases de Datos’ —as.nombre = ‘Bases de
Datos’—.
XAMPP es un paquete de aplicaciones que incluye varias cosas. Las dos más importantes para
nosotros son el Sistema Gestor de Base de Datos (SGBD) MySQL y un servidor Apache, que nos
ayudará a conectarnos a través de una aplicación web a nuestro SGBD para trabajar con él y
manejar los datos.
Página 24 de 113
XAMPP Installers and Downloads for Apache Friends →
https://www.apachefriends.org/es/index.html
Posteriormente, hay que desactivar la casilla relativa a «Learn more about Bitnami por XAMPP»
(en caso contrario, solo se abriría una página web que habría que cerrar).
Si en algún momento el Firewall de Windows solicita algún permiso, hay que concederlo.
Una vez instalado, desde el XAMPP Control Panel se han de ejecutar dos servicios: Apache y
MySQL, pulsando sobre el botón «Start». De ejecutarse correctamente, «Apache» y «MySQL»
de la columna «Module» tendrán un fondo verde, como en la imagen inferior. Ya se podrá
empezar a usar la aplicación XAMPP.
Seguidamente, le damos al botón «Admin» correspondiente a MySQL, con lo que se abrirá una
aplicación web local (http://localhost/phpmyadmin/) para administrar nuestras bases de datos.
Al ser local, no se puede acceder a ella desde internet.
Página 25 de 113
Una vez abierta la aplicación, en el menú superior hay que pulsar sobre «Bases de datos» y
«Crear base de datos».
Una vez realizado este paso, es posible comprobar las soluciones de los ejercicios ICA0002-S2-
C1-Ejercicios e ICA0002-S2-C2-Ejercicios, puesto que se pueden crear las estructuras de las
tablas para comprobar las selecciones que se hagan de los ejercicios.
Página 26 de 113
Tras copiar las tablas, hay que dirigirse a la base de datos recién creada en phpMyAdmin, pulsar
en «SQL» —situado en el menú superior—, pegar las tablas copiadas y clicar en «Continuar» —
botón situado en la parte inferior derecha—.
De no haber ningún fallo, en el menú de la izquierda deben aparecer las tablas creadas para el
primer ejercicio.
Ahora, para comprobar las selecciones de los ejercicios, hay que irse a «SQL» y escribir las
soluciones propuestas. Por ejemplo, la solución del ejercicio a), cuyo enunciado es «Selecciona
el identificador de las temporadas que han empezado entre el 2010 y el 2015», es la declaración
SQL SELECT id_temporada FROM temporada WHERE YEAR(fecha_inicio)
BETWEEN 2010 AND 2015;. Si se pega en phpMyAdmin y se da clic en «Continuar», se verá
que la sintaxis es correcta.
Página 27 de 113
En el caso de que se ponga una declaración errónea, como por ejemplo SELECT
id_teporada FROM temporada WHERE YEAR(fecha_inicio) BETWEEN 2010
AND 2015; , donde temporada está mal escrito, saldrá un mensaje de error.
Página 28 de 113
ICA0002-S02-C02
Los ejemplos se basan en este esquema relacional, donde por un lado está la tabla Equipo y por
otro la tabla Jugador. Se relacionan entre sí con la PK o FK (dependiendo de la tabla que se mire)
nombre_equipo.
En la tabla Equipo hay dos equipos, Barcelona y Madrid, con su presupuesto y el año de su
fundación.
En la tabla Jugador hay tres jugadores, con su DNI, nombre, apellidos, dorsal, posición y el
nombre del equipo en el que juegan.
GROUP BY
Página 29 de 113
Véase la siguiente declaración. Lo que hace el sistema es que cuando encuentra dos apellidos
iguales, los agrupa en una fila y solo muestra un resultado en vez de dos o tres repetidos. Así,
nótese que en el atributo apellido de la tabla Jugador hay dos Martínez, pero con GROUP BY
solo se muestra uno.
GROUP BY se puede aplicar sobre más de un atributo. En eso se diferencia de DISTINCT, que
solo se puede aplicar sobre un atributo. En este caso, lo que se hace es seleccionar los apellidos
—almacenados en los atributos apellido y apellido2— sin repeticiones en el conjunto de los dos
apellidos.
Para ello, se selecciona apellido y apellido2 de la tabla jugador, agrupando por apellido y
apellido2.
El resultado final es el conjunto de los dos apellidos, agrupados evitando repeticiones. En este
caso ninguno se repite, por lo que se muestran todos.
Página 30 de 113
Funciones de agregación
Las funciones de agregación permiten evaluar datos de las columnas para devolver algún tipo
de resultado que dé información.
COUNT()
Primeramente, se usa la función COUNT(), que devuelve el número de filas que coincide con
un criterio especificado; concretamente, lo que se hace es aplicar COUNT() al atributo DNI —
COUNT(DNI)— para saber cuántos DNI —y, por tanto, jugadores—hay.
En el SELECT también se añade el atributo nombre_equipo para saber a qué se vincula lo que
se está contando —es decir, a qué equipo hacen referencia los DNI contados por
COUNT(DNI)—.
Se pone FROM jugador porque tanto el atributo DNI como el atributo nombre_equipo
pertenecen a dicha tabla.
SUM()
Primeramente, se usa la función SUM(), que devuelve la suma total de una columna numérica;
concretamente, lo que se hace es aplicar SUM() al atributo dorsal —SUM(dorsal)— para
saber la suma de los dorsales.
En el SELECT también se añade el atributo nombre_equipo para saber a qué equipo hacen
referencia los dorsales sumados por SUM(dorsal).
Página 31 de 113
Se pone FROM jugador porque tanto el atributo dorsal como el atributo nombre_equipo
pertenecen a dicha tabla.
MIN()
En el siguiente ejemplo, se utiliza la función MIN() para devolver el valor mínimo del dorsal por
cada uno de los equipos.
Primeramente, se usa la función MIN(), que devuelve el valor más pequeño de la columna
seleccionada; concretamente, lo que se hace es aplicar MIN() al atributo dorsal —
MIN(dorsal)— para devolver el valor mínimo del dorsal.
En el SELECT también se añade el atributo nombre_equipo para saber a qué equipo hacen
referencia los dorsales.
Se pone FROM jugador porque tanto el atributo dorsal como el atributo nombre_equipo
pertenecen a dicha tabla.
Página 32 de 113
MAX()
En el siguiente ejemplo, se utiliza la función MAX() para devolver el valor más alto del dorsal
por cada uno de los equipos.
Primeramente, se usa la función MAX(), que devuelve el valor más alto de la columna
seleccionada; concretamente, lo que se hace es aplicar MAX() al atributo dorsal —
MAX(dorsal)— para devolver el valor más alto del dorsal.
En el SELECT también se añade el atributo nombre_equipo para saber a qué equipo hacen
referencia los dorsales.
Se pone FROM jugador porque tanto el atributo dorsal como el atributo nombre_equipo
pertenecen a dicha tabla.
AVG()
La función AVG() devuelve el valor medio de una columna numérica (devuelve la media).
Para calcular la media de los presupuestos de los equipos que hay en el sistema, se ha de hacer
así:
Página 33 de 113
En este caso, no se aplica el GROUP BY porque la media no se hace por cada uno de los equipos,
sino que se hace sobre el conjunto de los equipos. Esto es extensible a cualquiera de las
funciones de agregación: se pueden aplicar al conjunto de los datos que se devuelven o a un
conjunto reducido. Si se hace sobre un conjunto reducido, hay que hacer un GROUP BY, al
agrupar por equipo, por persona, por alumno, etc.
ICA0002-S2-C2-V2 Having
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102403)
Todos los ejemplos se basan en la siguiente base de datos, compuesta por tres tablas: Alumno,
Estudia y Asignatura, que se relacionan con las PK, FK DNI e id_asignatura.
The HAVING clause was added to SQL because the WHERE keyword cannot be used with
aggregate functions (traducción: la cláusula HAVING se añadió a SQL porque la palabra clave
WHERE no puede utilizarse con funciones de agregación).
Al no poder utilizar el WHERE, hace falta otra herramienta para aplicar esas condiciones. Esa
herramienta es HAVING.
El HAVING es una herramienta que SIEMPRE va relacionada con un GROUP BY. Nunca
encontraremos un HAVING sin un GROUP BY antes.
Ejemplo: media de las notas de las asignaturas siempre que esta sea superior a 5. El «siempre
que la media sea superior a 5» es una condición que implica la agrupación de las asignaturas
para ver si la media de estas agrupaciones es superior a 5. No se puede hacer la condición
antes de hacer la agrupación.
En este caso, lo que se haría es seleccionar, con SELECT, AVG(nota) para exponer la media
de la nota y mostrar el nombre de la asignatura utilizando el alias —as.nombre— de —
FROM—la tabla Estudia y la tabla Asignatura —estudia AS e, asignatura AS as—.
La tabla Alumno no es necesaria, puesto que no tengo ningún atributo de esta tabla.
Dentro del WHERE, se relacionan las tablas Estudia y Asignatura por medio del atributo
id_asignatura: WHERE e.id_asignatura = as.id_asignatura
Página 34 de 113
Por tanto, tras hacer la agrupación por asignatura —con GROUP BY—, se mira que la media de
nota de cada asignatura concreta sea superior a 5.
Código completo:
Otro ejemplo: media de las notas de las asignaturas con una id entre 1 y 5.
Dentro del WHERE, se relacionan las tablas Estudia y Asignatura por medio del atributo
id_asignatura: WHERE e.id_asignatura = as.id_asignatura
Finalmente, solo se muestra aquellos resultados cuyo id_asignatura esté entre —BETWEEN— 1
y 5. Esto se consigue con HAVING as.id_asignatura BETWEEN 1 AND 5
Por tanto, tras hacer la agrupación por asignatura —con GROUP BY—, se exponen solo aquellos
resultados cuyo id_asignatura esté entre 1 y 5.
Código completo:
Otro ejemplo: Media de las notas de las asignaturas siempre que esta sea superior a 5 y con
una id entre 1 y 5.
En este ejemplo, tenemos dos condiciones: que la nota sea superior a 5 y (AND) que la
id_asignatura esté entre 1 y 5.
Página 35 de 113
Dentro del WHERE, se relacionan las tablas Estudia y Asignatura por medio del atributo
id_asignatura: WHERE e.id_asignatura = as.id_asignatura
Finalmente, solo se muestra aquellos resultados cuya media sea superior a 5 y (AND) cuya
id_asignatura esté entre 1 y 5. Esto se consigue con el HAVING: HAVING AVG(nota) > 5
AND as.id_asignatura BETWEEN 1 AND 5
Código completo:
Los ejemplos se basan en esta base de datos, compuesta por las tablas Equipo y Jugador, que se
relacionan con la PK o FK (depende de la tabla que se mire) nombre_equipo.
La tabla Jugador tiene siete atributos, cada uno con sus valores: DNI, nombre, apellido, apellido2,
dorsal, posición y nombre_equipo.
ORDER BY
Página 36 de 113
La palabra clave ORDER BY ordena los registros en orden ascendente por defecto, aunque
también se puede indicar explícitamente la palabra clave ASC.
Para ordenar los registros en orden descendente, hay que utilizar la palabra clave DESC.
ORDEN ASCENDENTE: En primer lugar se sitúa el número más bajo y en último lugar el
número más alto.
ORDEN DESCENDENTE: En primer lugar se sitúa el número más alto y en último lugar el
número más bajo.
Ejemplo: Selecciona el nombre y dorsal de los jugadores y ordénalos según su dorsal de forma
ascendente (es decir, en primer lugar se sitúa el número más bajo y en último lugar el número
más alto).
Página 37 de 113
Ejemplo: Selecciona el nombre y dorsal de los jugadores y ordena según su dorsal de forma
descendente
Página 38 de 113
Ejemplo: Selecciona el nombre y apellido. Ordena a los jugadores según su apellido de la Z a
la A (descendente) y según su nombre de la A a la Z (ascendente)
Se implica a dos atributos —nombre y apellido—. Tras ORDER BY hay que poner uno detrás
de otro los atributos a través de los cuales se quiere ordenar. En este caso, se quiere ordenar
primero por el apellido de forma descendente, por lo que se pondría ORDER BY apellido
DESC y, tras separarlo con una , se pondría el atributo nombre —nombre ASC—
Código completo:
Como se aprecia, ORDER BY ordena primero a través de los apellidos de forma descendente,
de la Z a la A; y en el caso de que a través de los apellidos no pueda terminar de ordenar porque
hay dos iguales (como es el caso de Martínez), pasa a ordenar a través del nombre, en este caso
de forma ascendente, de la A a la Z. Por eso, Alfredo Martínez va antes que Manuel Martínez,
por el simple hecho de que, aunque comparten el apellido, el nombre de Alfredo comienza por
el principio del alfabeto, y el nombre clasifica de forma ascendente, de la A a la Z.
LIMIT
LIMIT no es una cláusula; es una función, pero es una función un tanto especial, ya que se
aplica siempre al final de todo de una selección. LIMIT es la última cosa que podemos
encontrar en una selección después de cualquiera de sus cláusulas u opciones.
Ejemplo: Selecciona nombre y apellido del primer jugador ordenado según el dorsal
LIMIT suele ir compaginado con el ORDER BY. Por ejemplo, cuando se quiere obtener el
primer jugador, el último jugador, los tres primeros jugadores, los tres últimos jugadores…
Cuando se tenga esta casuística, se ha de combinar un ORDER BY con un LIMIT.
Página 39 de 113
En este caso, se ha de mostrar únicamente el nombre y apellido del jugador que tenga el
dorsal más pequeño (orden ascendente).
Ejemplo: Selecciona el nombre y apellido del tercer jugador ordenado según el dorsal
Si se quiere mostrar el nombre y apellido del segundo, tercero o cuarto jugador, hay que usar
LIMIT OFFSET. Se reconoce porque LIMIT tiene dos parámetros:
• El primer parámetro es el OFFSET; esto es, cuántos resultados hay que saltar antes de
coger los resultados deseados.
• El segundo parámetro determina los resultados que se cogen.
Por ejemplo, LIMIT 2,1 quiere decir: «sáltate dos resultados y toma uno (es decir, toma
únicamente el tercero)».
SELECT nombre, apellido FROM jugador ORDER BY dorsal ASC LIMIT 2,1
ICA0002-S2-C2-V4 Conjuntos
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102405)
De estas tres operaciones, solo la UNION se puede operar realmente en el Sistema Gestor
MySQL. Por su parte, INTERSEC y MINUS no están implementados; por ello, solo se estudiarán
a nivel teórico.
Página 40 de 113
Los ejemplos se basan en esta base de datos, compuesta por las tablas Equipo y Jugador, que se
relacionan con la PK o FK (depende de la tabla que se mire) nombre_equipo.
UNION
UNION sirve para, teniendo dos conjuntos distintos —dos agrupaciones de resultados
distintas—, unir sus resultados.
Esto se puede aplicar a SQL, aunque hay que tener en cuenta algunas cosas:
Cuando trabajamos con conjuntos en SQL, hay que tener en cuenta tres cosas: los conjuntos
a operar tienen que tener siempre el mismo número de atributos; estos atributos tienen que
tener el mismo tipo (numérico, cadena de texto, fecha, etc.); y tienen que tener el mismo
dominio (es decir, el mismo significado; podemos unir, o hacer la interacción, o restar id, pero
no unir id con notas de alumnos; ambos son numéricos, pero no tienen el mismo dominio, por
lo que no tiene sentido unirlos).
Ejemplo: Selecciona el nombre de los equipos fundados antes del año 1900 o después del 2000
(con conjuntos).
Tenemos dos conjuntos separados, uno con los nombres de equipo con el año de fundación
anterior a 1900; y otro con los nombres de equipo con el año de fundación posterior a 2000.
Queremos unir ambos resultados. Podemos hacerlo mezclándolos con la cláusula UNION.
Sintaxis: el primer conjunto se pone entre paréntesis ( ), el segundo conjunto se pone entre
paréntesis ( ), y entre medias se pone UNION.
Página 41 de 113
INTERSEC
Con INTERSEC se obtienen los valores que están presentes en los dos conjuntos.
Ejemplo en SQL: Selecciona el nombre de los equipos fundados antes del año 1900 y con
presupuesto mayor a 1000000 (con conjuntos).
En SQL, si queremos hacer la INTERSEC entre los equipos fundados antes del año 1900 y con
presupuesto mayor a 1000000 (con conjuntos) —con el fin de obtener los nombres de equipo
que estén presentes en las dos selecciones—, la sintaxis a seguir es: el primer conjunto se pone
entre paréntesis ( ), el segundo conjunto se pone entre paréntesis ( ), y entre medias se pone
INTERSEC.
MINUS
MINUS sirve para quedarse con los valores del primer conjunto que no estén en el segundo.
Página 42 de 113
Ejemplo en SQL: Selecciona el nombre de los equipos fundados antes del año 1900 y que NO
tengan un presupuesto mayor a 3500000 (con conjuntos).
En SQL, si queremos hacer MINUS entre los equipos fundados antes del año 1900 y que NO
tengan un presupuesto mayor a 3500000, se toma en un conjunto los equipos fundados antes
del año 1900; y en otro conjunto los equipos que tienen un presupuesto mayor a 3500000.
Poniendo entre medias MINUS.
ICA0002-S03-C01
CREATE DATABASE
USE
Una vez creada la base de datos, si se quiere utilizar se usa el comando USE.
Los juegos de caracteres más conocidos son ASCII (que es la base sobre la que se crean los otros
dos), UTF-8 y LATIN1 (por defecto en MySQL). Cuando se crea una base de datos, se puede
definir qué juego de caracteres es el que se va a utilizar; cosa que también se puede hacer
cuando se crea una tabla, se puede elegir un juego de caracteres y compaginación específico
para una tabla, e incluso específico para un atributo.
Página 43 de 113
COLLATION o COMPAGINACIÓN
La compaginación es el conjunto de reglas que ayudan a comparar las distintas variables, los
distintos datos, dentro de las tablas, dentro de los atributos.
Hay tres tipos de compaginación: BIN (BINARY), CI (CASE INSENSITIVE) y CS (CASE SENSITIVE).
Obligatoriamente, todo juego de caracteres irá asociado como mínimo a una compaginación.
SHOW
Para mostrar los juegos de caracteres que tenemos dentro del sistema, dentro de MySQL, se usa
la herramienta SHOW.
SHOW COLLATION;
Muestra todas las compaginaciones de un juego de caracteres concreto (por ejemplo, latín 1):
Las compaginaciones más habituales que podemos encontrar con latín 1 son:
Página 44 de 113
CREATE DATABASE AVANZADO
Cuando se crea la base de datos también se puede definir por defecto cuál va a ser el juego de
caracteres o la compaginación a utilizar.
Supongamos que se desea crear la base de datos con juego de caracteres utf8 y compaginación
binaria:
Supongamos que se desea crear la base de datos con juego de caracteres utf8 y compaginación
española no sensible a las mayúsculas:
Para mostrar una página HTML correctamente, un navegador web debe saber qué juego de
caracteres utilizar.
ASCII fue el primer estándar de codificación de caracteres. ASCII definió 128 caracteres
diferentes que podían usarse en Internet: números (0-9), letras en inglés (AZ) y algunos
caracteres especiales como! $ + - () @ <>.
COLLATION O COMPAGINACIÓN
Información complementaria:
https://www.w3schools.com/html/html_charset.asp
https://dev.mysql.com/doc/refman/8.0/en/charset-mysql.html
Página 45 de 113
ICA0002-S3-C1-V2 Creación de las tablas
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102412)
ESTRUCTURA Y TIPOS
Dada la tabla Equipo, con una PK nombre_equipo y otros seis atributos —presupuesto,
ano_fundacion, es_federado, fecha_proximo_partido, momento_ultima_expulsion, siglas—,
hay que pasarla a código para crear la tabla.
Seguidamente, se van especificando los atributos junto a su tipo. En MySQL hay tres tipos de
datos principales: string (cadena), numeric (numérico) y date and time (fecha y hora). Cada uno
tiene numerosos Data Types.
En este caso, los atributos y sus tipos quedarían tal que así (nótese que al final de cada uno de
ellos se pone ,):
nombre_equipo VARCHAR(20),
presupuesto DECIMAL,
ano_fundacion INT,
es_federado BOOLEAN,
fecha_proximo_partido DATE,
momento_ultima_expulsion DATETIME,
siglas CHAR(3),
Página 46 de 113
BOOLEAN El tipo booleano sólo puede tener dos
valores: TRUE (verdadero) y FALSE (falso).
DATE Una fecha. Formato: YYYY-MM-DD. El rango
admitido es de ‘1000-01-01’ a ‘9999-12-31’.
DATETIME Una combinación de fecha y hora. Formato:
YYYY-MM-DD hh:mm:ss. El intervalo
admitido va de '1000-01-01 00:00:00' a
'9999-12-31 23:59:59'.
CHAR(size) Una cadena de longitud FIJA (puede contener
letras, números y caracteres especiales). El
parámetro size especifica la longitud de la
columna en caracteres, que puede ser de 0 a
255. Por defecto es 1.
Por su parte, VARCHAR(size) es dinámico. De este modo, solo ocupa en memoria el número
de caracteres que ocupe el atributo que se guarde ahí. Si nombre_equipo solo ocupa 10
caracteres, solo se ocupa memoria para esos 10 caracteres, y no para 20, que en es la longitud
máxima estipulada para VARCHAR en este ejemplo.
Se cierra con );
Página 47 de 113
La creación de tablas también la podemos complementar. Podemos crear una tabla si no existe.
Si ya existe no la creamos; no la sobrescribimos. Esto se consigue con:
CREATE TABLE IF NOT EXISTS nombre_de_la_tabla(
atributo tipo_de_datos_sql,
atributo tipo_de_datos_sql,
atributo tipo_de_datos_sql,
Página 48 de 113
Restricciones de SQL o SQL Constraints
Las restricciones son reglas y restricciones predefinidas que se aplican en una sola columna o en
varias columnas, relacionados a los valores permitidos en las columnas, para mantener la
integridad, precisión y confiabilidad de los datos de esa columna. En otras palabras, si los datos
insertados cumplen con la regla de restricción, se insertarán con éxito. Si los datos insertados
violan la restricción definida, la operación de inserción se cancelará.
Página 49 de 113
Una restricción PRIMARY KEY tiene
automáticamente una restricción UNIQUE.
Página 50 de 113
Todos los ejemplos sobre restricciones se basan en la siguiente base de datos, compuesta por
tres tablas: Alumno, Estudia y Asignatura. La PK de Alumno es DNI. La PK de Asignatura es
id_asignatura y la tabla Estudia es la que relaciona Alumno con Asignatura.
Todo ello se puede simplificar un poco, como se aprecia en el código superior derecho,
quitando la herramienta CONSTRAINT. Así, se puede indicar directamente PRIMARY
KEY(DNI) y UNIQUE(mail). Si no se utiliza CONSTRAINT, entonces no se identifica
a la restricción con un nombre único.
Página 51 de 113
Para crear la tabla Asignatura se ha optado por el siguiente código:
Se ha optado por utilizar CONSTRAINT, por lo que esta SQL PRIMARY KEY Constraint se nombra
como pk_asignatura: CONSTRAINT pk_asignatura PRIMARY
KEY(id_asignatura). Por tanto, se asigna el comando PRIMARY KEY al atributo
id_asignatura. Con esto se tendría la tabla Asignatura creada, con su Clave Primaria (PK).
DNI relaciona la tabla Estudia con la tabla Alumno. Y, por su parte, id_asignatura relaciona la
tabla Estudia con la tabla Asignatura. Por ello, los tipos de DNI —VARCHAR(9)— y de
id_asignatura —INT— son los mismos que los que ya hay establecidos en la tabla Alumno y en
la tabla Asignatura. ¿Por qué? Porque para relacionar una PK con una FK de otra tabla, el tipo
ha de ser el mismo, incluyendo el mismo tamaño.
Página 52 de 113
• Tabla Estudia. Tipo de dato de DNI (PK, FK): VARCHAR(9). Tipo de dato de
id_asignatura (PK, FK): INT.
• Tabla Alumno. Tipo de dato de DNI (PK): VARCHAR(9).
• Tabla Asignatura. Tipo de dato de id_asignatura (PK): INT.
Seguidamente, hay que definir la Clave Primaria (PK) de la tabla Estudia, que engloba el atributo
DNI e id_asignatura, puesto que es una Clave Primaria compuesta.
Para definir al Clave Primaria compuesta, dentro del paréntesis y separado por , hay que poner
todos los atributos que forman parte de la PK; esto es, (DNI, id_asignatura). Además,
se utilizado la herramienta CONSTRAINT:
Respecto a las Claves Foranas (FK), cuando se ha de definir una FK pasa lo mismo que son la PK
y el Índice Único*: puede definirse, optativamente, una CONSTRAINT para darle un nombre,
como si fuera un alias, a la FK, como las CONSTRAINT fk_alumno y fk_asignatura.
Seguidamente, para definir la FK propiamente, se pone:
FOREIGN KEY(atributo_que_tiene_la_Foreign_Key) REFERENCES
tabla_a_la_que_se_hace_referencia(atributo_al_que_se_hace_refere
ncia).
*Un Índice Único es usado para mantener la integridad de la información de las columnas sobre
las cuales es creado al asegurar que no hay valores duplicados en el índice clave, y la fila de la
tabla, sobre la cual el índice es creado. Un Índice Único se crea automáticamente cuando se
define una restricción de CLAVE PRIMARIA o CLAVE UNICA en las columnas específicas
Página 53 de 113
ICA0002-S3-C1-V3 Creación de las tablas. Propiedades
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102413)
Todos los ejemplos sobre las propiedades en la creación de las tablas se basan en la siguiente
base de datos, compuesta por tres tablas: Alumno, Estudia y Asignatura. La PK de Alumno es
DNI. La PK de Asignatura es id_asignatura y la tabla Estudia es la que relaciona Alumno con
Asignatura.
AUTO_INCREMENT
Los atributos autoincrementales solo se pueden dar en tipos enteros (INT) y que sean Claves
Primarias (PK) propias (es decir, que no sean Claves Primarias compuestas ni, a su vez, Claves
Foranas).
NOT NULL
Con la propiedad NOT NULL se estipula que un atributo de una tabla nunca será NULL.
Página 54 de 113
DEFAULT
DEFAULT indica qué valor por defecto va a tener un atributo cuando insertemos los datos de
un elemento si no le asignamos ningún valor.
O, dicho de otro modo, DEFAULT se utiliza para establecer un valor por defecto para una
columna. El valor por defecto se añadirá a todos los nuevos registros, si no se especifica otro
valor.
UNSIGNED
UNSIGNED se aplica a los tipos numéricos, obligando a que todos los números tengan que ser
positivos.
Es especialmente útil si se tiene en cuenta que para todos los tipos se reserva espacio para
guardar números positivos y negativos. Por ello, si no se han de guardar números negativos, se
puede utilizar el espacio que se reservaría a estos para los números positivos.
ZEROFILL
ZEROFILL indica que un atributo concreto, al guardarse, se va a rellenar con ceros por la
izquierda hasta el tamaño máximo del atributo.
Página 55 de 113
Valor ejemplo id_asignatura (atributo de tipo de dato numérico INT con la propiedad
ZEROFILL): 0000000001. Es decir, un seguido de ceros y el valor que le hayamos asignado
nosotros a id_asignatura; en este caso, 1.
El juego de caracteres también es una propiedad, tanto de los atributos como de las tablas.
Para un atributo puede definirse un CHARACTER SET y un COLLATE específico; de tal modo
que será independiente del juego de caracteres y de la compaginación de la tabla, de la base de
datos o del sistema.
En el código siguiente, tras el paréntesis final del código de creación de la tabla ), se define otro
CHARACTER SET con su COLLATE, que será el que tengan todos los atributos de la tabla
Asignatura, excepto nombre, puesto que a este se le ha especificado otro CHARACTER SET y
COLLATE particular.
COMMENT
COMMENT sirve para guardar comentarios en los atributos de una tabla. Puede servir para poner
un texto de ejemplo sobre qué podría estar guardado en ese atributo o para indicar a futuros
usuarios/administradores cómo se tiene pensado guardar dicha información.
MÚLTIPLES PROPIEDADES
Al sumar propiedades, hay que tener en cuenta que se refieran a tipos numéricos todas, o a
tipos de texto todas.
Página 56 de 113
Código de creación de la tabla Asignatura con AUTO_INCREMENT y NOT NULL:
¿Cómo se puede ver el código de creación de una tabla una vez ejecutada?
Por ejemplo:
El vídeo enseña cómo modificar una tabla ya creada para hacer distintas operaciones, como
añadir un atributo o añadir una Clave Forana.
La herramienta para modificar tablas ya creadas es ALTER. ALTER permite hacer un montón
de operaciones, como:
• Añadir PK
• Añadir FK
• Borrar PK
• Añadir un campo
• Modificar un campo
• Borrar un campo
Página 57 de 113
Los ejemplos sobre alteración de las tablas se basan en la siguiente base de datos (aunque
posteriormente se adjunta otra), compuesta por tres tablas: Alumno, Estudia y Asignatura. La
PK de Alumno es DNI. La PK de Asignatura es id_asignatura y la tabla Estudia es la que relaciona
Alumno con Asignatura.
• ALTER TABLE se utiliza para añadir, eliminar o modificar columnas en una tabla
existente.
• ALTER TABLE también se utiliza para añadir y eliminar diversas restricciones en una
tabla existente —ADD CONSTRAINT—.
Quedaría así:
Supongamos que se desea añadir una Clave Primaria compuesta a la tabla Asignatura. Los pasos
a seguir serían iguales que en el caso anterior, con la salvedad de que en PRIMARY KEY()
habría que añadir los dos (o más) atributos que conforman la PK compuesta; por ejemplo,
PRIMARY KEY (DNI, id_asignatura).
Página 58 de 113
Quedaría así:
De esta manera podemos establecer, fuera de la creación de las tablas, las FK. Esto es muy útil
ya que, cuando creamos las tablas, para poder crear las FK las tablas a las que estamos haciendo
referencia tienen que existir. Así, podemos crear todas las tablas solo definiendo las PK y
posteriormente añadir las FK.
Con ALTER TABLE también se puede añadir la FK con comportamiento de UPDATE y DELETE,
puesto que es lógico que si actualizamos un campo referenciado la relación se actualice, y que
si borramos un campo referenciado la relación elimine. No tiene sentido tener una relación en
Estudia con una asignatura inexistente.
Página 59 de 113
Código para añadir la FK id_asignatura con comportamiento de UPDATE y DELETE:
Con ellas, la propia base de datos impide que se realicen operaciones que provocarían
inconsistencias.
RESTRICT: Es el comportamiento por defecto, que impide realizar modificaciones que atentan
contra la integridad referencial.
CASCADE: Borra los registros de la tabla dependiente cuando se borra el registro de la tabla
principal (en una sentencia DELETE), o actualiza el valor de la clave secundaria cuando se
actualiza el valor de la clave referenciada (en una sentencia UPDATE).
SET NULL: Establece a NULL el valor de la clave secundaria cuando se elimina el registro en
la tabla principal o se modifica el valor del campo referenciado.
Los siguientes ejemplos se realizan sobre la base de esta base de datos, compuesta por tres
tablas:
• Hospital, con una PK múltiple compuesta por nombre y pais; este último atributo
también es una Clave Forana, lo que indica que viene de otra tabla que no aparece en
el trozo de esquema suministrado, pero tampoco hace falta.
• Medico, con una PK llamada DNI.
• Hospital_Medico, tabla de relación entre Hospital y Medico que tiene tres PK, FK.
o Una PK, FK múltiple, conformada por nombre y pais, vinculados a la tabla
Hospital.
o Y una PK, FK simple, DNI, vinculado a la tabla Medico.
En este caso interesa la FK múltiple, ya que hasta el momento no hemos visto cómo se procesa.
Página 60 de 113
Cuando se tiene una Clave Primaria (PK) compuesta, dentro de la PK se establecen los atributos
que forman parte de esta clave:
Hay que tener en cuenta que los atributos entre paréntesis de FOREIGN KEY y los atributos
entre paréntesis de REFERENCES deben estar en el mismo orden. Si se invirtieran, se estaría
relacionando el nombre de Hospital_Medico con el pais de Hospital, lo que es incorrecto. Hay
que relacionar el nombre de Hospital_Medico con el nombre de Hospital, y el pais de
Hospital_Medico con el pais de Hospital.
Página 61 de 113
Para borrar la PK de una tabla:
ADD/DROP FIELD
ALTER TABLE también permite añadir o borrar campos (atributos) a una tabla.
Tras el tipo de dato podrían añadirse cualquier de las propiedades vistas anteriormente.
Ejemplo: En la tabla Asignatura se quiere añadir un campo parar guardar los créditos de las
materias. Por tanto, el SQL Data Type es INT.
Página 62 de 113
MODIFY
MODIFY se utiliza para modificar un campo ya creado; por ejemplo, para cambiarle el tipo de
dato o para añadirle propiedades.
CHANGE
Página 63 de 113
ICA0002-S3-C1-V5 Renombrado, borrado y vistas
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102415)
RENAME
DROP TABLE
Página 64 de 113
Borrar una tabla comprobando antes si existe o no (si se elimina sin existir el sistema dará
error):
DROP DATABASE
DROP DATABASE sirve para borrar una base de datos. Hay que utilizarlo con precaución.
VISTAS
Las vistas son estructuras que permiten guardar el resultado de una selección. Una vista nunca
puede llamarse igual que una tabla, ya que a nivel interno el Sistema Gestor de Bases de Datos
(SGBD) guarda las vistas en el mismo lugar que las tablas, lo que permite hacer vistas de otras
vistas.
Las vistas pueden ser actualizables o no. Para que una vista pueda ser actualizable; es decir, que
se puedan insertar, modificar y borrar datos directamente a través de la vista sin tener que ir a
la tabla, han de cumplirse ciertas condiciones, como que la vista solo pueda hacer referencia a
una tabla, y no se puede tener ni agrupados ni condiciones ni agrupación ni ningún otro
elemento que compacte filas, como la función de DISTINCT. De cumplirse estas condiciones,
la vista podrá ser actualizable.
Página 65 de 113
CREATE VIEW
Para crear una vista en la que guardar el resultado de una selección —SELECT—, hay que seguir
la siguiente sintaxis:
Para crear una vista en la que guardar el resultado de una selección —SELECT—, o
reemplazarla de existir, hay que seguir la siguiente sintaxis:
Ejemplo: Crear una vista o reemplazarla si existe de los nombres y apellidos de los alumnos:
SELECT VIEW
Si se desea visualizar el contenido de una vista, puede hacerse de la misma manera que con las
tablas, haciendo un SELECT de la vista.
Página 66 de 113
Para mostrar solo una columna:
Se acepta cualquier tipo de operación que tengamos en una selección: ordenar los datos,
filtrarlos, etc.
DROP VIEW
Desde phpMyAdmin se pueden crear y configurar bases de datos gráficamente (en el vídeo hay
unos ejemplos), aunque lo que nos interesa es hacerlo por código.
Primeramente, en XAMPP Control Panel hay que darle a «Start» en Apache y MySQL.
Seguidamente, hay que darle al botón «Admin» correspondiente a MySQL, lo que abrirá una
ventana del navegador con phpMyAdmin. A continuación, en el menú superior hay que pulsar
en «SQL».
La base de datos, «s3_c1_ej1», aparece en la columna de la izquierda. Hay que clicar sobre ella
para acceder.
Página 67 de 113
El código se encuentra en el archivo «S03-C01-E-sol-ej1.sql», que forma parte de ICA0002-S3-
C1-Ejercicios.
Página 68 de 113
A continuación, se crean las tablas:
Página 69 de 113
Si se pincha sobre la base de datos en el menú de la izquierda, se verán las tablas:
Para ver las Claves Foranas de cada una de las tablas, hay que pinchar sobre cada una de ellas
(por ejemplo, sobre «clasificación») → «Estructura» → «Vista de relaciones», donde aparecen
definidas todas las Claves Foranas, con un formulario que permite, incluso, cambiarlas. Desde
ahí se puede comprobar si las Claves Foranas creadas están bien indicadas o no.
Para borrar una tabla con código —por ejemplo, la de federación—, tras acceder a la base de
datos y clicar en «SQL», hay que introducir la siguiente declaración:
No obstante, el sistema no dejará eliminar la tabla federacion, porque hay una FK en otra tabla
que depende de federacion. Por ello, si se desea borrar federacion, antes se ha de borrar equipo,
que es la tabla que depende de federacion:
Página 70 de 113
ICA0002-S03-C02
Para insertar información en la tabla usaremos el comando INSERT INTO, que tiene distintos
modos de uso.
INSERT Directo
El primer modo de uso de INSERT INTO es el llamado INSERT Directo, que es cuando
tenemos todos los atributos de la tabla en el mismo orden a la hora de hacer la inserción de
datos. Es decir, insertamos en la tabla equipo un registro con todos los atributos en el mismo
orden que el orden de creación de la tabla.
INSERT Indirecto
En el caso del INSERT Indirecto, lo que se hace es definir qué atributos se desean insertar y
rellenar. En este tipo de INSERT, todos los atributos que insertemos deben ser, como mínimo,
los obligatorios; es decir, la PK y si tenemos algún atributo que sea con la propiedad NOT NULL.
De otra manera, no nos dejaría insertarlos.
Los atributos que no definamos quedarán para ese registro definidos como NULL.
Página 71 de 113
En este caso, insertamos en la tabla equipo un registro con solo los atributos nombre_equipo,
presupuesto y siglas con sus valores concretos. El resto de atributos que no hemos marcado
quedarían, de momento, como NULL.
Casos especiales
Para ver algunos casos especiales, utilizaremos el esquema con las tablas Equipo y Jugador,
donde Equipo tiene varios jugadores. Tenemos una relación de PK FK entre Equipo y Jugador.
Cuando se hacen INSERT con FK’s, hay que tener en cuenta varias cosas. Por ejemplo, para
poder definir en la tabla Jugador la FK con el nombre del equipo en el que juega, este equipo
tiene que existir. Si no existe este equipo, no puede crearse.
En este caso, primero se crea un equipo (Sporting La Salle) y luego se crea un jugador, definiendo
en su FK nombre_equipo el equipo en el que juega (Sporting La Salle).
También puede crearse un jugador sin rellenar la FK, puesto que si no se ha establecido la
propiedad NOT NULL para el atributo nombre_equipo, no haría falta rellenarlo.
Página 72 de 113
Lo que no puede hacerse nunca es crear un jugador con un valor en esa FK —en este caso,
nombre_equipo— que no exista; esto es, que no haya sido creado previamente.
A continuación, se va a utilizar el esquema inferior, conformado por tres tablas: Alumno, Estudia
y Asignatura.
Para poder rellenar la tabla Estudia se ha de tener el alumno al que se quiere hacer referencia
creado en la tabla Alumno, y la asignatura a la que se quiere hacer referencia en la tabla
Asignatura. De cumplirse estas condiciones, podrá hacerse la relación entre el alumno y la
asignatura.
Página 73 de 113
INSERT con AUTO_INCREMENT
Cuando se hace un INSERT con un campo autoincremental —en este caso, suponemos que la
id_asignatura es autoincremental; lo que significa que cuando se creó la tabla id_asignatura se
definió como id_asignatura INT AUTO_INCREMENT,— podemos hacer varias cosas.
La primera, establecer un valor para ese identificador definido por nosotros.
Así, se puede poner en id_asignatura el número 2. ¿Por qué? Porque, aunque el campo sea
autoincremental, podemos definir un valor concreto, siempre que no exista:
El campo id_asignatura también se puede dejar como NULL. El propio sistema detectará que
tiene que autogenerar en ese campo un identificador. Generará un identificador numérico
autoincremental:
Página 74 de 113
MULTI-INSERT
Multi-insert quiere decir que con el mismo comando de inserción podemos insertar más de un
registro. Si tenemos algún problema o algún error con cualquiera de los registros, ninguno se
insertará.
Como ejemplo, insertamos en la tabla Asignatura dos grupos de valores entre paréntesis ( ):
INSERT INTO asignatura VALUES (5, ‘FOL’, NULL), (6, ‘EIE’, NULL);
El vídeo enseña cómo modificar datos que tengamos guardados en nuestras tablas de una base
de datos.
Los ejemplos se hacen sobre la base de esta base de datos, que tiene tres tablas: Alumno, Estudia
y Asignatura.
SQL UPDATE Statement: La sentencia UPDATE se utiliza para modificar los registros
existentes en una tabla.
SET: La cláusula SET establece los nuevos valores para las columnas indicadas.
WHERE: La cláusula WHERE sirve para seleccionar las filas que queremos modificar.
Página 75 de 113
Ejemplo: Respecto a la tabla Alumno, se desea actualizar el nombre y apellido del alumno con
DNI 1111111A a Anna Fernández:
Ejemplo: Actualizar la descripción de las 4 primeras asignaturas ordenando por id con el texto
‘Asignatura troncal’:
O se elimina la columna entera para que pase a no existir más en la base de datos, o se actualiza
el campo y se pone a NULL.
Para ver cómo se borran los datos de una tabla nos basaremos en el siguiente esquema,
compuesto por tres tablas: Alumno, Estudia y Asignatura.
Página 76 de 113
Ejemplo: Borrar los datos de la tabla Alumno:
Borrar un elemento concreto (todas las condiciones que se utilizaban en el WHERE con el
SELECT pueden utilizarse en el WHERE con DELETE FROM):
DELETE FROM puede complementarse con ORDER BY y LIMIT. Pero no con GROUP BY
ni HAVING, ya que no podemos borrar filas agrupadas.
Ejemplo: Borrar los 4 primeros alumnos ordenando por el primer apellido de la A a la AZ:
DELETE FROM: Entre DELETE y FROM no se pone nunca nada, ni asterisco ni nada.
Una vez en phpMyAdmin, hay que seleccionar la base de datos sobre la que se va a trabajar y
pulsar en «SQL», situado en el menú superior.
El vídeo utiliza como ejemplo el contenido del archivo «S03-C02-E-sol-ej1.sql», que forma parte
de «S03-C02-E-sol.zip»; es decir, de ICA0002-S3-C2-Ejercicios.
Primero, se copia este fragmento de código en el formulario SQL de phpMyAdmin. Con ello, se
consiguen dos filas por cada una de las tablas:
Luego, se entra en la tabla federacion y, mediante formato gráfico, se borra la Federacion Inglesa
de Futbol.
Página 77 de 113
Luego, se reingresa en la tabla federacion, se pulsa en «SQL» y se ve cómo aparecen una serie
de botones, como SELECT *, SELECT, INSERT, UPDATE, DELETE, que simplifican el trabajo con
código.
ICA0002-S04-C01
Una subconsulta es una consulta dentro de otra consulta. Es decir, es una consulta que actúa
como condición de otra consulta —de otro SELECT—.
Dentro de una selección —SELECT—, las consultas pueden aparecer en tres sitios:
Página 78 de 113
¿Qué tipos de subconsultas hay?
Para ver cómo funcionan las subconsultas básicas nos basaremos en el siguiente esquema,
compuesto por tres tablas: Alumno, Estudia y Asignatura.
La tabla Alumno contiene tres alumnos, con los atributos DNI (que es la PK), nombre, apellido,
apellido2, fecha_nacimiento y mail.
Página 79 de 113
La tabla Asignatura contiene dos asignaturas, con los atributos id_asignatura, nombre y
descripcion.
La tabla Estudia relaciona qué alumno —DNI— estudia qué asignatura —id_asignatura—, con
su nota —nota—.
Esto se puede hacer de dos maneras: con una subconsulta o sin subconsulta.
• Sin subconsulta.
Primeramente, hay que tener presente que se crea un ALIAS —AS— para las tablas:
Se selecciona el DNI de la tabla Alumno —SELECT a.DNI FROM alumno—, pero también
se selecciona la tabla Estudia para poder contar en cuántas asignaturas están matriculados los
alumnos. SELECT a.DNI FROM alumno AS a, estudia AS e.
Dentro del WHERE se relacionan las tablas Alumno y Estudia a través del DNI. WHERE a.DNI
= e.DNI.
Mediante GROUP BY se agrupa por DNI, puesto que la respuesta que queremos obtener es por
persona —es decir, por DNI—. GROUP BY a.DNI.
Código completo:
Página 80 de 113
• Con subconsulta.
Hay que tener presente que se crea un ALIAS —AS— para las tablas:
En primer lugar, seleccionamos el DNI de la tabla Alumno. SELECT a.DNI FROM alumno
AS a.
En el siguiente WHERE, se iguala el DNI de la tabla Estudia al DNI de la tabla Alumno, que es el
que hemos seleccionado previamente en SELECT a.DNI —WHERE e.DNI = a.DNI—.
De esta forma, solo contamos las asignaturas que pertenezcan al alumno que estamos
mostrando.
Y, en el caso de que las asignaturas sean iguales o mayores a 2 —>= 2—, se mostrará el DNI
del alumno. Es decir, esta subconsulta solo nos devuelve un número, pero se ejecuta cada vez,
según los DNI que tengamos en la tabla Alumno; es decir, si tenemos tres DNI en la tabla Alumno,
contará tres veces, una por cada fila. Contará cuántas asignaturas tiene el alumno con el primer
DNI, cuántas asignaturas tiene el alumno con el segundo DNI y cuántas asignaturas tiene el
alumno con el tercer DNI.
Código completo:
Ejemplo: Devuelve el DNI de los alumnos con la mayor nota registrada en cualquier asignatura:
Hay que tener presente que se crea un ALIAS —AS— para las tablas:
Página 81 de 113
Se selecciona el DNI de la tabla Alumno con la función DISTINCT, para evitar sacar el mismo
DNI más de una vez (por si la misma persona ha sacado la máxima nota en más de una
asignatura). SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1.
Se relaciona la tabla Alumno y la tabla Estudia, para poder relacionar al alumno con las notas
que ha sacado
En la condición de la subconsulta, decimos que la nota que ha sacado el alumno que tenemos
que mostrar tiene que ser igual a la nota máxima —y aquí la subconsulta— de todas las notas
que tenemos guardadas. Es decir, de todas las notas que tenemos en la tabla Estudia. WHERE
a.DNI = e1.DNI AND e1.nota = (SELECT MAX(e2.nota) FROM estudia AS
e2); .
Por tanto, si la nota del alumno que quiero mostrar es igual a la nota máxima, quiere decir que
ese alumno ha sacado la mayor nota de todos los alumnos de todas las asignaturas. Eso implica
que, si hay dos alumnos que han sacado la mayor nota, por ejemplo, 10, en la misma asignatura,
o en asignaturas distintas, los dos son resultados válidos, porque los dos han sacado la máxima
nota. Por tanto, nos mostraría los dos resultados.
Código completo:
Ejemplo: Devuelve el DNI de los alumnos con la nota más baja registrada en cualquier
asignatura:
En este caso, usando la función MIN() en la subconsulta, miraría cuál es la nota mínima que
tenemos registrada en nuestra base de datos y la compararía con la nota que ha ido sacando
cada alumno en cada una de las asignaturas en las que está matriculado. En el caso de que la
nota del alumno sea igual a la nota mínima, es que esa nota es la más baja de todas las que
tenemos guardadas y, por tanto, se mostraría. Si tenemos más de un alumno con la nota más
baja, nos mostraría más de un resultado.
Código completo:
Tanto para la primera selección de subconsulta —SELECT MAX()— como para la segunda —
SELECT MIN()—, siempre se nos devuelve un único valor. Por eso es una subconsulta básica.
Como nos devuelve un único valor, lo podemos comparar con algo directamente: comparamos
una nota con un valor numérico que sacamos de ese MAX() o de ese MIN().
A continuación, se ve otro ejemplo con una base de datos más compleja, en formato Schema.
Hay cinco tablas —Empleado, Departamento, Lugar_Departamento, Proyecto y
Proyecto_Empleado, que relaciona los proyectos con los empleados que trabajan en ellos—.
Página 82 de 113
Ejemplo: Selecciona todos los datos de los empleados que trabajen en tres o ningún proyecto
y muestra el resultado en orden descendente según el DNI.
«Selecciona todos los datos de los empleados» → SELECT e.* FROM Empleado AS e
Además, hay dos condiciones: tenemos que mirar que cada uno de los empleados esté
trabajando en tres proyectos o (OR) esté trabajando en cero proyectos. Estas dos condiciones
deberán ser subconsultas.
WHERE
(SELECT COUNT(ID_proyecto) FROM Proyecto_Empleado AS p2
WHERE p2.DNI=e.DNI) = 0
OR
(SELECT COUNT(ID_proyecto) FROM Proyecto_Empleado AS p2
WHERE p2.DNI=e.DNI) = 3
Página 83 de 113
Código completo:
SELECT e.*
FROM Empleado AS e
WHERE
(SELECT COUNT(ID_proyecto) FROM Proyecto_Empleado AS p2
WHERE p2.DNI=e.DNI) = 0
OR
(SELECT COUNT(ID_proyecto) FROM Proyecto_Empleado AS p2
WHERE p2.DNI=e.DNI) = 3
ORDER BY e.DNI DESC;
ICA0002-S4-C1-V3 Subconsultas IN
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102432)
Subconsultas IN
Página 84 de 113
Operador SQL IN → El operador IN permite seleccionar múltiples valores en una cláusula
WHERE.
• Sin subconsulta.
o Alias para la tabla alumno → a
o Alias para la tabla estudia → e
Se selecciona el DNI y el nombre, que son las dos cosas que se quieren mostrar, de la tabla
Alumno y de la tabla Estudia. SELECT a.DNI, a.nombre FROM alumno AS a,
estudia AS e.
Lo relacionamos, ya que relacionándolo sabremos que ese alumno está matriculado en alguna
asignatura. WHERE a.DNI = e.DNI.
Agruparemos por DNI para no devolver el mismo resultado más de una vez. GROUP BY
a.DNI;
Código completo:
Página 85 de 113
• Con subconsulta de tipo IN.
o Alias para la tabla alumno → a
o Alias para la tabla estudia → e
Seleccionamos el DNI y el nombre, pero tomando solo de la tabla Alumno. SELECT a.DNI,
a.nombre FROM alumno AS a
Utilizamos la función IN para comprobar si el DNI del alumno que estoy mirando —uno cada
vez—, está en la lista de personas —es decir, en la lista de DNI—, de gente que está matriculada.
Por tanto, si esa persona está matriculada, quiere decir que está estudiando y que estará dentro
de la selección de la subconsulta. Y, por lo tanto, filtrará positivamente a la condición. WHERE
a.DNI IN (SELECT e.DNI FROM estudia AS e WHERE e.DNI = a.DNI);
Nótese que WHERE e.DNI = a.DNI es para evitar que la subconsulta tenga más resultados
de los necesarios. Es decir, se quitan directamente los DNI que sé que no me van a servir, que
no sean iguales que el propio. Es decir, o tendré el mismo DNI que ya tengo en la consulta general
una vez o más de una vez, o no lo tendré. La consulta del WHERE no me haría falta ponerla, pero
tampoco molesta.
Por tanto, la función de IN sirve para comprobar que alguna cosa, algún valor, esté dentro de
una lista de valores.
Para este caso se usa NOT IN. Para este ejemplo comprobaríamos que el DNI de la persona
que yo estoy seleccionando no esté en la lista de DNI que tenemos dentro de la tabla Estudia.
Ejemplo: Devuelve el DNI y nombre de los alumnos de la siguiente lista: 2222222B, 3333333C,
4444444D.
Otra cosa que también podemos hacer con la función de IN es, en vez de comprobar con una
subconsulta; es decir, con una selección dentro de la función de IN, lo hacemos con una lista de
valores.
Directamente podemos comprobar que el DNI esté dentro de una lista de DNI que le damos
directamente —en este caso, son 2222222B, 3333333C, 4444444D—.
Así pues, comprobamos que el DNI del alumno esté en una lista concreta de DNI. De ser así, se
filtra el resultado como positivo y se muestra en pantalla. En el caso contrario, no se mostraría.
Ejemplo: Devuelve los nombres y primer apellido de alumnos que se repitan conjuntamente
en otro alumno.
Página 86 de 113
conjuntamente en otro alumno. Es decir, se devuelven los nombres y apellidos que se repiten
en alumnos distintos (alumnos que se llaman igual).
Se selecciona nombre y apellido de la tabla Alumno y se mira que ese nombre y apellido, en
conjunto los dos valores, estén dentro (IN) de la lista de nombres y apellidos también de la tabla
Alumno, exceptuando —con WHERE a2.DNI <> a.DNI— el mismo propio, porque la misma
persona, con ella misma, siempre tiene el mismo nombre y el mismo apellido.
Ejemplo: Selecciona el ID y el nombre del proyecto que disponga de empleados cuyo nombre
contenga «T» y (AND) que trabajen en un departamento que esté localizado en una ciudad
que empiece con una «B».
Luego, miro que la ID_proyecto esté en una lista de ID_proyecto que sean proyectos donde tengo
empleados cuyo nombre contiene una T. Por tanto, en la primera subconsulta hago una
selección de ids de proyecto —SELECT pe.ID_proyecto—; por tanto, una lista de ids de
proyecto, que tengan como mínimo un empleado con una letra T en su nombre.
Página 87 de 113
WHERE p1.ID_proyecto IN
(SELECT pe.ID_proyecto
FROM Proyecto_Empleado AS pe, Empleado AS e
WHERE pe.DNI=e.DNI AND e.nombre LIKE “%T%”)
Segunda subconsulta: hago una lista de ids de proyecto —SELECT p2.ID_proyecto— que
tengan departamentos que estén localizados en un lugar que empiece por B.
AND p1.ID_proyecto IN
(SELECT p2.ID_proyecto
FROM Proyecto AS p2, Lugar_Departamento AS l
WHERE p2.dept=l.ID_dept AND lugar_dept LIKE “B%”);
Las dos subconsultas devuelven una lista de valores, una lista de ids, y la comparo con la id que
yo estoy seleccionando, con la ID_proyecto de la tabla Proyecto. En este caso, si está en las dos
listas; es decir, si es un empleado que tiene una T en su nombre y su departamento está
localizado en una ciudad que comienza por B, entonces se muestra por pantalla, gracias a la
selección —SELECT p1.ID_proyecto, p1.nom_proyecto FROM Proyecto AS
p1—.
INTERSECT
IN permite simular la operación INTERSECT, que no se puede utilizar dentro de MySQL. Por
tanto, para hacer una intersección tenemos que codificar una operación de IN, como se ve en
la imagen superior. Dicha intersección devuelve los nombres de los alumnos donde ese nombre
aparezca alguna vez como primer apellido para cualquier persona dentro de la base de datos.
Página 88 de 113
Se selecciona el nombre de la tabla de alumno:
Código completo:
MINUS
Con MINUS podemos hacer que se devuelvan los nombres de alumnos que NO aparezcan como
primer apellido en cualquier persona de nuestra base de datos.
Pero MINUS no se puede hacer con SQL, así que hay que recurrir a NOT IN.
Donde (WHERE) ese nombre (a.nombre) no esté (NOT IN) en la selección de apellidos de la
tabla Alumno (subconsulta) SELECT a2.apellido FROM alumno AS a2);
Es decir, cuando el valor del nombre (a.nombre) no esté en ninguno de los apellidos
(a2.apellido) de los alumnos que constan en la base de datos, entonces se muestra. Por
tanto, se muestran solo los nombres que no se repitan dentro de los apellidos.
Página 89 de 113
Código completo:
ANY significa que la condición será verdadera si la operación es verdadera para cualquiera de
los valores del rango.
Página 90 de 113
Otra explicación:
ANY significa que, para que una fila de la consulta externa satisfaga la condición especificada,
la comparación se debe cumplir para al menos un valor de los devueltos por la subconsulta.
Por cada fila de la consulta externa se evalúa la comparación con cada uno de los valores
devueltos por la subconsulta y si la comparación es TRUE para alguno de los valores, encones
ANY es verdadero; y si la comparación no se cumple con ninguno de los valores de la consulta,
entonces ANY da FALSE. A no ser que todos los valores devueltos por la subconsulta sean
nulos, en tal caso ANY dará NULL.
Ejemplo: Devuelve el DNI de todos los alumnos excepto el/los más joven/es:
Así, si la fecha de nacimiento del alumno no es mayor a cualquier fecha de nacimiento de las
que tengamos, quiere decir que es el más joven. En el caso de que haya algunos alumnos
diferentes con la misma fecha de nacimiento, y que sea la más actual —por tanto, son los más
jóvenes—, se cumplirá la condición y se mostrará el resultado con uno o varios alumnos,
dependiendo de si la fecha de nacimiento se repite o no para los más jóvenes.
Página 91 de 113
Ejemplo: Selecciona el DNI y el sueldo de los empleados, excepto el/los que ganan más.
• Subconsulta básica.
o Alias para la tabla Empleado → e
o Alias para la tabla Empleado (subconsulta) → e2
Primeramente, se selecciona el DNI y el sueldo del empleado, que es lo que se quiere mostrar,
de la tabla Empleado:
Donde —WHERE— este sueldo —e.sueldo— sea menor —<— (y aquí viene la subconsulta)
que el sueldo máximo —MAX()— de la tabla Empleado — (SELECT MAX(e2.sueldo)
FROM Empleado AS e2); —
Código completo:
En el caso de que el sueldo de cada persona sea menor que el sueldo máximo, quiere decir que
no es el que cobra más, por lo que se mostrará.
Al ser una subconsulta básica, solo se devuelve un resultado, que es el que se comprueba cada
vez con el sueldo de cada uno de los empleados.
Primeramente, se selecciona el DNI y el sueldo del empleado, que es lo que se quiere mostrar,
de la tabla Empleado:
Página 92 de 113
Donde —WHERE— el sueldo —e.sueldo— sea menor —<— que cualquiera —ANY— (y aquí
viene la subconsulta) de los sueldos de la tabla de Empleado — (SELECT a2.sueldo FROM
Empleado AS e2);—.
Código completo:
De esta manera, se comprueba el sueldo de cada empleado —cada fila de la tabla empleado—
con todas las otras filas —todos los otros sueldos— y, si es menor que al menos uno de esos
sueldos, quiere decir que no es el sueldo máximo. Por lo tanto, se mostraría.
Página 93 de 113
SQL ALL Operator
ALL significa que la condición será verdadera sólo si la operación es verdadera para todos los
valores del rango.
Con el modificador ALL, para que se cumpla la condición, la comparación se debe cumplir con
cada uno de los valores devueltos por la subconsulta.
Donde —WHERE— la fecha de nacimiento de esa persona —de ese DNI que se quiere mostrar—
—a1.fecha_nacimiento— sea mayor o igual —>=— a todas —ALL— (y aquí viene la
subconsulta) las fechas de nacimiento que tenemos en la tabla de Alumno —(SELECT
a2.fecha_nacimiento alumno AS a2.DNI<>a1.DNI);—. Se obvia la
comprobación con la propia fecha de nacimiento ya que no tiene sentido comprobarla con la
misma fecha de nacimiento del mismo usuario.
Con esta subconsulta la función ALL se preocupa que la condición que aplico a la subconsulta,
en este caso >=, se cumpla para todos los resultados que encuentre en la subconsulta; es decir,
comprueba la parte de la izquierda —la parte de la consulta general— con todas las fechas de
nacimiento y la condición obliga a que se cumpla en todas. A diferencia de ANY, puesto que con
ANY con que solo se cumpla una vez ya basta.
Ejemplo: Devuelve el DNI de los alumnos con la mayor nota registrada en cualquier asignatura:
Como en este caso los DNI se pueden repetir ya que la misma persona puede tener la máxima
nota en distintas asignaturas, lo que se hace es aplicar la función de DISTINCT al DNI que se
muestra para evitar repeticiones.
• Subconsulta básica:
Se selecciona el DNI con la función DISTINCT de la tabla Alumno; y la tabla Estudia, para saber
qué alumnos estudian qué asignaturas:
Página 94 de 113
A continuación, se comprueba —WHERE— que esa nota que han sacado los alumnos sea igual
—a.DNI = e1.DNI AND e1. nota =— (y aquí viene la subconsulta) a la nota máxima
de todas las notas que hay dentro de la tabla Estudia —(SELECT MAX(e2.nota) FROM
estudia AS e2);—.
Código completo:
Se selecciona el DNI con la función DISTINCT de la tabla Alumno; y la tabla Estudia, para saber
qué alumnos estudian qué asignaturas:
A continuación, se comprueba —WHERE— que la nota de cada uno de los alumnos que hay en
la tabla sea mayor o igual —>=— a todas —ALL— las notas que hay dentro de la tabla Estudia:
WHERE a.DNI = e1.DNI AND e1.nota >= ALL (SELECT e2.nota FROM estudia
AS e2);
En el caso de comprobarlo con la misma nota, no nos afecta, ya que la nota del mismo alumno
siempre será igual a su nota, por lo que no hace falta que la filtremos.
Código completo:
Página 95 de 113
Los siguientes ejemplos se basan en esta base de datos:
Ejemplo: Selecciona el DNI y el sueldo de el/los empleado/s que gane/n más y el/los que
menos.
Para ello hay que hacer dos subconsultas dentro de la selección. Una para mirar los que ganan
más y otra para mirar los que ganan menos.
Donde —WHERE— este sueldo —e.sueldo— sea mayor o igual —>=— a todos —ALL— (y
aquí viene la primera subconsulta) los sueldos de la tabla Empleado —(SELECT e2.sueldo
FROM Empleado AS e2—. Se pone también la condición de no comprobar el DNI con el DNI
de la persona que se está cogiendo esa vez —WHERE e.DNI <> e2.DNI)—, aunque no
haría falta, ya que el sueldo de una persona siempre será igual a su mismo sueldo, por lo que
siempre se va a cumplir.
WHERE
e.sueldo >= ALL (SELECT e2.sueldo FROM Empleado AS e2 WHERE e.DNI <>
e2.DNI)
Por otro lado —OR— también se mira que el sueldo —e.sueldo— sea menor o igual —<=—
a todos —ALL— (y aquí viene la segunda subconsulta) los sueldos de la tabla Empleado —
(SELECT e2.sueldo FROM Empleado AS e2— Se pone también la condición de no
comprobar el DNI con el DNI de la persona que se está cogiendo esa vez —WHERE e.DNI <>
e2.DNI);—.
OR
e.sueldo <= ALL (SELECT e2.sueldo FROM Empleado AS e2 WHERE e.DNI <>
e2.DNI);
Página 96 de 113
Por tanto, lo que se está haciendo es que se cumpla una de las dos subconsultas; una de las dos
condiciones: o que el sueldo sea más grande o igual a todos los sueldos —por lo tanto, que sea
el que cobra más/o los que cobran más— o más pequeño o igual a todos los sueldos —por lo
tanto, que sea el que cobra menos/o los que cobran menos—.
EXISTS y NOT EXISTS se emplean para determinar si hay o no datos en una lista de valores.
Página 97 de 113
Ejemplo: Devuelve el DNI y nombre de los alumnos matriculados en alguna asignatura:
Esto se puede hacer de muchas maneras; algunas de ellas sin subconsulta y otras de ellas con
subconsulta.
• Sin subconsulta.
o Alias para la tabla alumno → a
o Alias para la tabla estudia → e
Se selecciona el DNI y el nombre, que es lo que se quiere mostrar, de la tabla Alumno; y la tabla
Estudia para ver en qué asignaturas están matriculados los alumnos.
Y se agrupa por DNI para filtrar los repetidos; por si hay algún alumno que está matriculado en
más de una asignatura.
GROUP BY a.DNI;
Código completo:
• Con subconsulta:
Se comprueba que para una persona —para un DNI concreto— existe algún registro en la tabla
Estudia con su DNI.
Con EXISTS, no hay que relacionar nada de fuera de la subconsulta con nada dentro de forma
directa. Sí que se pueden relacionar atributos en el WHERE de la subconsulta de forma indirecta.
Es decir, al igual que la función ALL o ANY tenían un operador con algún atributo de la tabla
principal o de las tablas principales para compararlo, o al igual que IN tenía algún atributo con
el que comparábamos con los atributos de dentro, con la función de EXISTS eso no pasa.
Con EXISTS lo que se hace es mirar si existe algún registro. De hecho, estamos seleccionando
el DNI en la subconsulta, pero podríamos seleccionar todos los atributos; no hace falta
seleccionar el DNI; solo se mira que haya registros en la tabla Estudia que correspondan al DNI
de la persona que se está mirando. Por eso la condición del WHERE de la subconsulta. Si existen
registros es que está matriculado en alguna asignatura; da igual en cuál; solo es preciso saber
que está matriculado en alguna.
Por tanto:
Página 98 de 113
Se selecciona el DNI y el nombre, que es lo que se quiere mostrar, de la tabla Alumno.
Código completo:
Para devolver los alumnos no matriculados, primero se selecciona el DNI y el nombre, que son
los que se desean mostrar, de la tabla Alumno:
Ahora, se quiere determinar que NO existen registros en la tabla Estudia donde el DNI de los
registros de la tabla Estudia sea igual al DNI de la persona que se está mirando. Si no existe
ningún registro, es que la persona no está matriculada en ninguna asignatura. Esto se consigue
con:
Código completo:
Página 99 de 113
SELECT * FROM asignatura AS as
Donde —WHERE— no existe —NOT EXISTS— (ahora empieza la subconsulta) ningún registro
en la tabla Estudia — (SELECT * FROM estudia AS e— donde —WHERE— la
id_asignatura de la tabla Estudia coincida con la id_asignatura de la tabla Asignatura —
e.id_asignatura = as.id_asignatura);—. Si en la tabla Estudia no hay ningún
registro con la id_asignatura de una asignatura concreta, es que esa asignatura no ningún
alumno matriculado.
Ejemplo: Selecciona el DNI y sueldo de los empleados que trabajan en todos los proyectos:
Para este caso hay que hacer una doble subconsulta anidada. Es decir, una consulta donde hay
una subconsulta y, dentro de esta subconsulta, hay otra subconsulta.
Subconsulta
Subconsulta
Y miramos que no exista ningún proyecto en el que no trabaje el empleado. Es decir, si no existe
ningún proyecto en el que no trabaje el empleado en concreto, querrá decir que ese empleado
trabaja en todos los proyectos.
Por lo tanto, «lingüísticamente», lo que vamos a hacer en la primera subconsulta es decir «no
existe ningún proyecto…». Por eso, seleccionamos todos los atributos de la tabla Proyecto.
WHERE
NOT EXISTS (SELECT * FROM Proyecto AS p
…DONDE —WHERE— «…no exista relación entre el empleado en cuestión y los proyectos»:
WHERE
NOT EXISTS (SELECT * FROM Proyecto_Empleado AS pe WHERE e.DNI = pe.DNI
AND pe.ID_proyecto = p.ID_proyecto));
Código completo:
Por tanto, se comprueba con la doble negación que no tenemos ningún proyecto en el que no
esté trabajando cada empleado en concreto. O, lo que es lo mismo, lo que estamos diciendo es
que el empleado en cuestión que cumpla estas condiciones está trabajando en todos los
proyectos.
Donde —WHERE— el DNI de la tabla Empleado coincida —=— con el DNI de la tabla
Proyecto_Empleado:
WHERE
e.DNI = pe.DNI
GROUP BY
e.DNI
HAVING
COUNT(pe.ID_proyecto) = (SELECT COUNT(p.ID_proyecto) FROM Proyecto AS
p);
Un ejemplo de JOIN es el que se puede ver en la captura superior, sobre la base de datos de
Equipo y Jugador. El JOIN sirve para juntar información o para juntar los resultados de dos o
más tablas.
El JOIN es el resultado de juntar dos tablas, indicándole cómo se tienen que relacionar entre
ellas. Una operación de JOIN siempre va a equivaler a un FROM con más de una tabla con una
condición o supliendo la condición de WHERE, por el cual le decimos al sistema cómo se
relacionan las dos tablas.
• INNER JOIN
• OUTER JOIN
Además, dentro del OUTER JOIN hay distintas tipologías: LEFT, RIGHT, FULL. Más adelante
las veremos.
• CROSS JOIN
• STRAIGHT_JOIN
Nos vamos a centrar en el INNER JOIN y en el OUTER JOIN, con todas sus opciones y
características ya que son los más importantes.
INNER JOIN selecciona los registros que tienen valores coincidentes en ambas tablas.
Un INNER JOIN no deja de ser una forma de juntar dos o más tablas, indicando cuál es el
atributo que las relaciona.
Por tanto, el mismo SELECT que podemos hacer seleccionando DNI, nota y asignatura de la
tabla Alumno, relacionando en el WHERE el DNI de la tabla Alumno y el DNI de la tabla Estudia
puede hacerse utilizando un JOIN
El siguiente SELECT, que consiste en seleccionar DNI, nota y asignatura de la tabla Alumno,
relacionando en el WHERE el DNI de la tabla Alumno y el DNI de la tabla Estudia…
… puede hacerse utilizando un JOIN. En este caso, en el FROM y entre paréntesis ( ) se junta,
utilizando JOIN, la tabla de Alumno con la tabla de Estudia. Y, utilizando el comando ON, se le
indica que estas dos tablas se juntan a través de la igualación de sus DNI.
Lo hecho con JOIN se puede hacer exactamente igual con INNER JOIN, puesto que JOIN e
INNER JOIN son sinónimos:
De la misma manera que juntamos dos tablas, también podemos juntar más de dos tablas. En el
siguiente ejemplo, tenemos una selección donde nos muestra el DNI de la tabla Alumno, la nota
de la tabla Estudia y el nombre de la asignatura de la tabla Asignatura. Por tanto, en FROM
debemos coger la tabla Alumno, la tabla Estudia y la tabla Asignatura.
Luego, se relaciona los DNI de la tabla Alumno con los DNI de la tabla Estudia.
y (AND) las id_asignatura de la tabla Estudia con las id_asignatura de la tabla Asignatura.
Código completo:
Lo anterior se puede hacer con JOIN. Lo que se hace es que dentro de FROM y entre paréntesis
( ) se juntan las tablas Alumno, Estudia y Asignatura. Y con ON se especifica cómo se relacionan
todas estas tablas, igualando los DNI y (AND) igualando las asignaturas. Hecho esto, seguimos
teniendo una condición, que es la nota menor a 5, y que no es una condición de juntada de
tablas, sino que es una condición normal, por lo que no puede ir con los JOIN, tiene que ir
con WHERE.
Así, el JOIN no tiene por qué suplir la condición de WHERE. Si tenemos condiciones que no
sean de juntar tablas el WHERE seguirá apareciendo haciendo su función.
NATURAL JOIN
Dentro del INNER JOIN tenemos un caso particular: el NATURAL JOIN, que puede servir
para simplificar la forma en que relacionamos las tablas utilizando el JOIN.
La particularidad que tiene el NATURAL JOIN es que no tenemos por qué indicarle la
igualación de los atributos que relacionan las dos tablas. Él mismo se encargará de encontrarlo.
Es importante especificar que el NATURAL JOIN no está presenta en todos los SGBD.
Hay que juntar la tabla de Alumno y la tabla de Estudia para poder mostrar y filtrar la información
deseada.
También se puede utilizar de forma más concreta, donde aparte de juntar las tablas con el
NATURAL JOIN le decimos que atributo tiene que usar para junta esas tablas. Él se encargará
de igualar los atributos que sean, dependiendo de las PK y FK que haya en dichas tablas.
Es importante remarcar que el uso del NATURAL JOIN a veces puede conducir a errores,
ya que si tenemos tablas con muchas relaciones, es fácil que el NATURAL JOIN se equivoque
a la hora de escoger qué relación es la adecuada para nuestro caso de uso.
El OUTER JOIN siempre va relacionado con una categoría de él mismo: LEFT, RIGHT o FULL.
LEFT OUTER JOIN lo que hace es juntar dos tablas, al igual que hacíamos con un JOIN
normal. La diferencia es que con LEFT OUTER JOIN cuando juntamos dos tablas cuando
tenemos registros en la tabla de la izquierda que no se relacionan con ningún registro de la tabla
de la derecha, al devolver las repuestas seguirán apareciendo, y va a relacionar los atributos de
la tabla de la izquierda cuando no se encuentre ninguna relación con la tabla de la derecha con
valores NULL.
En el apartado de FROM, donde hay que indicar la relación entre las tablas, se utiliza el LEFT
OUTER JOIN y relacionamos la tabla de Alumno con la tabla de Estudia. En este caso, lo que
se provoca es que la tabla de Alumno, cuando no esté relacionada con ningún valor en la tabla
de Estudia, siga apareciendo en el resultado, pero combinado con un valor NULL. En este caso,
al mostrar el DNI y la media de la nota, la media de la nota, en el caso de que el alumno no tenga
asignatura y no se pueda crear la media, aparecerá en la columna de la media de la nota un valor
NULL.
Código completo:
LEFT OUTER JOIN es exactamente lo mismo que LEFT JOIN. Por tanto, el código superior
se podría escribir también así:
En ambos casos, obtendríamos el siguiente resultado: los DNI de los alumnos combinados con
sus medias. Si un alumno no tiene media porque no está en ninguna asignatura, como es el caso
del usuario con el segundo DNI, en la media de la nota aparece un NULL.
Al juntar dos tablas utilizando un RIGHT OUTER JOIN, se provoca que si la tabla de la derecha
no está relacionada con ningún valor de la tabla de la izquierda, aparezca como resultado, pero
relacionado con un valor NULL.
En este caso, devolvemos la media de las notas de asignatura y el nombre de las asignaturas,
incluyendo esas asignaturas que no tienen alumnos. Al hacer la media por asignatura se hace un
GROUP BY por id_asignatura de la tabla Asignatura y tenemos que juntar tanto la tabla Estudia
como la tabla Asignatura. Si las juntamos en este orden, primero la tabla Estudia y luego la tabla
Asignatura, podemos utilizar un RIGHT OUTER JOIN y provocar que la tabla Asignatura, si
no se relaciona con ninguna fila de la tabla de Estudia, esa asignatura concreta también aparezca
relacionada con un valor NULL.
Código completo:
RIGHT OUTER JOIN es exactamente lo mismo que RIGHT JOIN. Por tanto, el código
superior se podría escribir también así:
En ambos casos, obtendríamos el siguiente resultado: la media de las notas y el nombre de las
asignaturas. En este caso, hay una asignatura —JAVA— que no tiene ninguna persona
matriculada, por lo que la media de la nota aparece como NULL.
FULL OUTER JOIN: No puede escribirse directamente sobre el SGBD MySQL. Pero, aunque
no se pueda escribir, FULL OUTER JOIN puede ejecutarse combinando un LEFT OUTER
JOIN y un RIGHT OUTER JOIN a través de un conjunto de unión —UNION—.
El FULL OUTER JOIN, por lo tanto, no es nada más y nada menos que una combinación de
LEFT OUTER JOIN con RIGHT OUTER JOIN. Es decir, se juntan una o más tablas y da
igual que alguna de las tablas, ya sea la de la derecha o la de la izquierda, no esté relacionada
con ningún valor al otro lado de la relación. Si esto pasa, los valores concretos se van a rellenar
con valores NULL.
Ejemplo: Devuelve los DNI y nombres de asignaturas de los alumnos matriculados, incluyendo
los alumnos sin asignaturas y las asignaturas sin alumnos.
En este caso, con LEFT OUTER JOIN solventaríamos el caso de los alumnos sin asignaturas,
y con el RIGHT OUTER JOIN solventaríamos el caso de las asignaturas sin alumnos. Al unir
el resultado combinaríamos los dos resultados, simulando el FULL OUTER JOIN.
Código completo:
Print output:
Por lo tanto, el resultado es la combinación de LEFT OUTER JOIN con RIGHT OUTER
JOIN. En el caso de tener alguna persona —a.DNI— que no esté matriculada en ninguna
asignatura, se relacionaría con un NULL. En el caso de tener alguna asignatura —as.nombre—
que no esté relacionada con ninguna persona, que no tenga ninguna persona matriculada, se
relacionaría también con NULL.
Como ocurre con NATURAL JOIN, NATURAL OUTER JOIN no está implementado en
todos los SGBD. Además, ha de tratarse con cuidado, ya que, en algunos casos, si tenemos tablas
con muchas relaciones se puede equivocar al escoger él mismo la relación por la cual solucionar
la selección que le estamos pidiendo.
Código completo:
También se puede hacer utilizando el comando USING, indicándole que tiene que juntar esas
dos tablas utilizando el DNI. Él se encargará de ir a buscar la PK FK adecuada para juntarlos.
Código completo:
Ejemplo: Devuelve las medias de nota por asignatura y el nombre de las mismas incluyendo
las que no tienen alumnos.
Igual que existe el NATURAL LEFT JOIN también existe el NATURAL RIGHT JOIN, que
es exactamente lo mismo, pero a la inversa.
En este caso, tendremos el mismo comportamiento que con RIGHT JOIN, pero sin hacer falta
indicar cuál es la relación entre las tablas que estamos relacionando. Podemos utilizar la sintaxis
de NATURAL RIGHT JOIN o NATURAL RIGHT JOIN y el comando USING para indicar el
atributo por el cual tenemos que relacionar las tablas.