Está en la página 1de 113

ICA0 M02-UF2: Lenguajes SQL: DML y DDL - Realizado por Ramón Alarcón Sánchez

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.

¿Cómo seleccionar todos los nombres de equipo guardamos? Con


SELECT nombre_equipo FROM equipo;. De esta forma, se devuelven todos los equipos
guardados en el sistema, produciéndose este resultado:

Cláusulas

La selección está formada por varias partes, denominadas cláusulas.

SELECT → Define qué se quiere obtener; qué queremos que nos devuelva el sistema.

FROM → Define dónde está guardada la información que se quiere obtener.

WHERE → Son las condiciones que queremos utilizar para filtrar lo que nos devuelve el sistema.

GROUP BY → Permite agrupar resultados.

HAVING → Permite aplicar condiciones sobre los grupos.

ORDER BY → Ordena los resultados.

Página 1 de 113
De estas seis cláusulas, hay dos obligatorias cuando se escribe un SELECT: SELECT y FROM.

Cláusulas según ejecución

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:

• Menor que: <


• Mayor que: >
• Mayor o igual que: >=
• Menor o igual que: <=
• Igual que: =
• Igual que aplicado a texto: =‘texto’
• Diferente que: <>

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

SELECT nombre_equipo FROM equipo WHERE presupuesto < 1000000;

• MAYOR QUE (>): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea mayor que (>) 1000000

SELECT nombre_equipo FROM equipo WHERE presupuesto > 1000000;

• MAYOR O IGUAL QUE (>=): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea mayor o igual que (>=) 1000000

SELECT nombre_equipo FROM equipo WHERE presupuesto >= 1000000;

• MENOR O IGUAL QUE (<=): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea menor o igual que (<=) 1000000

SELECT nombre_equipo FROM equipo WHERE presupuesto <= 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

SELECT nombre_equipo FROM equipo WHERE presupuesto = 1000000;

• IGUAL A ‘TEXTO’ (= ‘texto’): Obtener el DNI de los jugadores, de la tabla Jugador,


puesto que el atributo DNI está en dicha tabla, cuyo nombre sea igual a Juan (=
‘texto’)

SELECT DNI FROM jugador WHERE nombre = ‘Juan’;

Página 3 de 113
• DIFERENTE QUE (<>): Obtener el nombre de los equipos, de la tabla Equipo, cuyo
presupuesto sea diferente a (<>) 1000000

SELECT nombre_equipo FROM equipo WHERE presupuesto <> 1000000;

Operador de comparación LIKE

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

• Tiene 5 letras donde la segunda es una A: LIKE ‘_ A _ _ _’;

• Tiene al menos dos letras (o más): LIKE ‘_ _ %’;

Supongamos el siguiente esquema relacional:

• EMPIEZA POR: Obtener el nombre de los equipos, de la tabla Equipo, cuyo nombre
empiece por B → LIKE ‘B%’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo 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%’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo NOT LIKE ‘B%’;

• TERMINA POR: Obtener el nombre de los equipos, de la tabla Equipo, cuyo nombre
termine por A → LIKE ‘%A’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo LIKE ‘%A’;

• CONTIENE: Obtener el nombre de los equipos, de la tabla Equipo, cuyo nombre


contenga la letra A → LIKE ‘%A%’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo LIKE ‘%A%’;

• TIENE 5 LETRAS: Obtener el nombre de los equipos, de la tabla Equipo, que tengan 5
caracteres. → LIKE ‘_ _ _ _ _’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo LIKE ‘_ _ _ _ _’;

• TIENE 5 LETRAS DONDE LA SEGUNDA ES UNA A: Obtener el nombre de los equipos, de


la tabla Equipo, que tengan 5 caracteres, siendo el segundo una
A → LIKE ‘_ A _ _ _’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo LIKE ‘_ A _ _ _’;

• 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 ‘_ _ %’;

SELECT nombre_equipo FROM equipo WHERE nombre_equipo LIKE ‘_ _ %’;

Página 5 de 113
Operador de comparación BETWEEN

BETWEEN sirve para comprobar que algo está dentro de un rango.

• Comprobar que algo esté dentro del rango entre 1000000 y 2000000:
BETWEEN 1000000 AND 2000000;

Supongamos el siguiente esquema relacional:

• Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto esté dentro
del rango entre 1000000 y 2000000 → BETWEEN 1000000 AND 2000000;

SELECT nombre_equipo FROM equipo WHERE presupuesto BETWEEN 1000000 AND


2000000;

Operadores lógicos

Son tres: AND | OR | NOT

Supongamos el siguiente esquema relacional:

AND → Indica una suma de condiciones; y han de cumplirse ambas.

• 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%’;

SELECT nombre_equipo FROM equipo WHERE 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%’;

SELECT nombre_equipo FROM equipo WHERE presupuesto > 1000000 OR


nombre_equipo LIKE ‘B%’;
NOT → Indica que una condición NO ha de cumplirse. Así, da la opción de negar cualquiera de
las condiciones que pongamos en una selección; en este caso, en el WHERE.

• Obtener el nombre de los equipos, de la tabla Equipo, cuyo presupuesto NO (NOT)


esté por encima de 1000000 (o lo que es lo mismo, que sea menor/esté por debajo de
1000000) → WHERE (para establecer las condiciones a utilizar para filtrar lo que
devuelve el sistema) NOT (presupuesto > 1000000)

SELECT nombre_equipo FROM equipo WHERE NOT (presupuesto > 1000000)

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;

SELECT nombre_equipo FROM equipo WHERE presupuesto > 1000000 AND


nombre_equipo LIKE ‘B%’ AND ano_fundacion < 1900;

Combinación de operadores lógicos (ejemplo, combinar AND y OR dentro del WHERE)

• 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);

SELECT nombre_equipo FROM equipo 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) es un elemento totalmente opcional que ayuda a poner un alias/sobrenombre a un


atributo o a una tabla.

El alias puede utilizarse en dos sitios: en el SELECT y en el FROM.

• Alias (AS) en el SELECT:

SELECT nombre_equipo AS nombre_del_equipo FROM equipo;


Print output:

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.

• Alias (AS) en el FROM:

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.

SELECT e.nombre_equipo FROM equipo AS e WHERE e.presupuesto > 1000000;

• Referencias sin alias:

Referencias como la que se acaba de tratar pueden hacerse sin el alias, indicando directamente
el nombre de la tabla.

De este modo, si se escribe equipo.nombre_equipo, se sabe que se está haciendo


referencia al atributo nombre_equipo de la tabla Equipo.

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.

SELECT equipo.nombre_equipo FROM equipo WHERE equipo.presupuesto >


1000000;

Función DISTINCT (DISTINCT)

Se usa para devolver valores distintos/diferentes.

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.

SELECT DISTINCT (apellido) FROM jugador;


Print output:

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.

SELECT DISTINCT (apellido) AS apellidos FROM jugador;


Print output:

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.

SELECT * FROM equipo;


Print output:

Página 10 de 113
Otros ejemplos

Selecciones multiatributo

Como se ha visto hasta el momento, se puede seleccionar un atributo de la tabla, o con el


operador * seleccionarlos todos. Pero también se pueden seleccionar algunos atributos
concretos; dos, tres o los que sean.

La sintaxis es: SELECT atributo1, atributo2, atributo3 FROM tabla

En el siguiente caso, se seleccionan dos atributos: nombre_equipo y presupuesto de la tabla


equipo. Se mostrarán ambos atributos junto con sus valores.

SELECT nombre_equipo, presupuesto FROM equipo


Print output:

Selecciones con valores NULL

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.

SELECT * FROM jugador WHERE nombre_equipo IS NULL;


SELECT * FROM jugador WHERE nombre_equipo = 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

SELECT * FROM jugador WHERE nombre_equipo IS NOT NULL;


SELECT * FROM jugador WHERE nombre_equipo <> NULL;

Página 11 de 113
Selecciones con operaciones matemáticas en el SELECT

Pueden aplicarse operaciones de matemáticas básicas en los atributos de la selección.

Por ejemplo, pueden mostrarse los equipos y sus presupuestos sumando un millón extra a
dichos presupuestos:

La sintaxis es: SELECT atributo+suma FROM tabla; → SELECT atributo+1 FROM


tabla;

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:

SELECT nombre_equipo, presupuesto+1000000 FROM equipo;

Ejemplo: Mostrar los equipos con sus presupuestos aplicando un -20% para quitar los
impuestos (también se le aplican un alias AS):

SELECT nombre_equipo, presupuesto*(1-0.2) AS presupuesto_sin_impuestos


FROM equipo;

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

A tener en cuenta (Fuente https://www.w3schools.com/sql/sql_dates.asp)

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:

DATE - format YYYY-MM-DD

DATETIME - format: YYYY-MM-DD HH:MI:SS

TIMESTAMP - format: YYYY-MM-DD HH:MI:SS

YEAR - format YYYY or YY

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

DATE - format YYYY-MM-DD

DATETIME - format: YYYY-MM-DD HH:MI:SS

SMALLDATETIME - format: YYYY-MM-DD HH:MI:SS

TIMESTAMP - format: a unique number

Página 13 de 113
NOW()

La función NOW() devuelve un formato DATETIME, con la estructura YYYY-MM-DD hh:mm:ss

NOW() → DATETIME → YYYY-MM-DD hh:mm:ss

Puede utilizarse, por ejemplo, para seleccionar los nombres y apellidos de los alumnos con
fecha de nacimiento menor a la fecha actual.

SELECT nombre, apellido FROM alumno WHERE fecha_nacimiento < NOW();

CURRENT_DATE()

CURRENT_DATE() se asemeja a NOW(), con la diferencia de que CURRENT_DATE()


devuelve un formato DATE, con la estructura YYYY-MM-DD. Por tanto, solo compararemos con
la fecha del día, sin tener en cuenta las horas, los minutos y los segundos.

CURRENT_DATE() → DATE → YYYY-MM-DD

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.

SELECT nombre, apellido FROM alumno WHERE fecha_nacimiento <


CURRENT_DATE();

Página 14 de 113
YEAR(‘date’), YEAR(‘datetime’) o YEAR(atributo)

Las comillas simples ‘ ’ se usan cuando se utiliza con date —YEAR(‘date’)— o


datetime —YEAR(‘datetime’)—

Las comillas simples ‘ ’ no se usan cuando YEAR() modifica los valores de un atributo
—YEAR(fecha_nacimiento)—

YEAR(‘date’) o YEAR(‘datetime’) devuelve de un tipo DATE (YYYY-MM-DD) o de un


tipo DATETIME (YYYY-MM-DD HH:MI:SS) solo el año.

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.

Si se escribe la sentencia SQL SELECT YEAR('1994/08/31 09:08');, el resultado es


1994

Puede usarse un alias (AS) para estilizar el resultado: SELECT YEAR('1994/08/31


09:08') AS Year;

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)—.

SELECT DNI, YEAR(fecha_nacimiento) FROM alumno;

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.

SELECT DNI FROM alumno WHERE YEAR(fecha_nacimiento) < 1990;

MONTH(‘date’), MONTH(‘datetime’) o MONTH(atributo)

Las comillas simples ‘ ’ se usan cuando se utiliza con date —MONTH(‘date’)— o


datetime —MONTH(‘datetime’)—

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.

SELECT nombre, apellido FROM alumno WHERE MONTH(fecha_nacimiento) = 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…

SELECT DNI FROM alumno WHERE MONTH(fecha_nacimiento) = MONTH(NOW());

SELECT DNI FROM alumno WHERE MONTH(fecha_nacimiento) =


MONTH(CURRENT_DATE());

DAY(“date”), DAY(‘date’) o DAY(atributo)

En W3Schools, el ejemplo que aparece con DAY(“date”)


(https://www.w3schools.com/sql/func_mysql_day.asp) va entre comillas dobles “ ”, pero
también funciona con comillas simples ‘ ’.

No se usan comillas cuando DAY() modifica los valores de un atributo —


DAY(fecha_nacimiento)—

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 ejemplo, el resultado de la sentencia SQL DAY(“date”) es 31.

He probado a ejecutar la misma sentencia con comilla simples DAY(‘date’) y el resultado


es el mismo, 31.

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.

SELECT nombre, apellido FROM alumno WHERE DAY(fecha_nacimiento) = 1;

Página 18 de 113
Funciones de texto

LENGTH()

La función LENGTH() (en español, «longitud») tiene un comportamiento similar al operador


LIKE (que, recordemos, se utiliza en cadenas de texto; por ello, LIKE siempre va acompañado
de comillas simples ‘ ’).

De este modo, si deseo que se muestren los nombres de aquellas asignaturas que tengan 5
caracteres, puedo hacer lo siguiente:

Con LIKE:

SELECT nombre FROM asignatura WHERE nombre LIKE ‘_ _ _ _ _’;

Con LENGTH():

SELECT nombre FROM asignatura WHERE LENGTH(nombre) = 5;

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:

SELECT nombre FROM asignatura WHERE LENGTH(nombre) > 5;

CONCAT()

Concatena cadenas de texto, variables o atributos.

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.

SELECT CONCAT(nombre, apellido, apellido2) FROM alumno WHERE DNI =


‘11111111A’
Print output:

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

SELECT CONCAT(nombre, ‘ ’, apellido, ‘ ’, apellido2) AS


Nombre_Completo FROM alumno WHERE DNI = ‘11111111A’
Print output:

ICA0002-S2-C1-V4 Selecciones multitabla


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102396)

Selecciones con 2 tablas

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 .

SELECT DNI, ano_fundacion FROM equipo, jugador;


Print output:

❌¡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.

SELECT DNI, ano_fundacion FROM equipo, jugador WHERE


equipo.nombre_equipo = jugador.nombre_equipo;
Print output:

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

SELECT DNI, ano_fundacion FROM equipo AS e, jugador AS j WHERE


e.nombre_equipo = j.nombre_equipo;
Print output:

A continuación, se seleccionan todos los atributos de la tabla Jugador de aquellos equipos


fundados antes del 1900; implicando así a la tabla Equipo, que es la que tiene el atributo
ano_fundacion.

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

No se ha de olvidar que en la cláusula WHERE se ha de poner la relación entre Equipo y Jugador


a través del atributo nombre_equipo e.nombre_equipo = j.nombre_equipo. Del
mismo modo, hay que especificar que se filtren los resultados en función del año de fundación
de los equipos, que debe ser igual o anterior a 1900 —ano_fundacion <= 1900—.

SELECT j.* FROM equipo AS e, jugador AS j WHERE e.nombre_equipo =


j.nombre_equipo ano_fundacion <= 1900;
Print ouput: Se muestra todo el contenido de los jugadores del Barcelona, ya que el Barcelona
es, de los dos equipos que hay, el único que su año de fundación es menor o igual a 1900.

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’—.

SELECT j.* FROM jugador AS j WHERE j.nombre_equipo = ‘Barcelona’;


Print output:

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.

A modo de ejemplo, se selecciona el nombre y apellido de los alumnos de la asignatura «Bases


de Datos». El nombre de la asignatura está en la tabla Asignatura, y el nombre y apellidos de los
alumnos están en la tabla Alumno. Es decir, necesito ambas tablas, y para relacionarlas requiero
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’—.

SELECT a.nombre, a.apellido FROM alumno AS a, estudia AS e, asignatura


AS as WHERE a.DNI = e.DNI AND e.id_asignatura = as.id_asignatura AND
as.nombre = ‘Bases de Datos’;

ICA0002-S2-C1-V5 Instalación y uso básico de XAMPP


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102397)

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

Una vez descargado y ejecutado el EXE, comenzará el proceso de instalación. No es necesario


instalar todos los componentes, pero hay cuatro que sí son indispensables: Apache, MySQL, PHP
y phpMyAdmin, que se remarcan en la imagen inferior.

Se deja el directorio de instalación por defecto (en mi caso, C:\xampp).

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

Se le pone un nombre y se le da clic a «Crear». Si no ha habido ningún error, en el menú de la


izquierda ha de aparecer la base de datos recién creada (en este caso, se llama
«ramon_alarcon»).

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.

El vídeo utiliza como ejemplo las soluciones de ICA0002-S2-C1-Ejercicios. Tras descargar y


descomprimir el ZIP ICA0002-S02-C01-E-sol.zip, que contiene tres archivos con extensión SQL
(código de lenguaje de consulta estructurado), se abre el primer archivo de soluciones —puede
hacerse con Notepad++— y se copia la primera parte del archivo, que tiene las tablas necesarias
para validar las sintaxis de los SELECT, como se ve en la imagen inferior. Esta parte del código
no está explicado; se explicará más adelante, pero sirve para validar las soluciones 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

ICA0002-S2-C2-V1 Group by y Funciones de Agregación


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102402)

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

Evitar repeticiones. La primera utilidad de la cláusula GROUP BY es evitar repeticiones.

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.

SELECT apellido FROM jugador GROUP BY apellido;


Print output:

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.

Selección de los apellidos sin repeticiones:

SELECT apellido, apellido2 FROM jugador GROUP BY apellido, apellido2;


Print output:

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 suelen utilizarse con GROUP BY.

Las funciones de agregación permiten evaluar datos de las columnas para devolver algún tipo
de resultado que dé información.

COUNT()

El siguiente ejemplo se basa en la suposición de que queremos contar cuántos jugadores


tenemos por equipo.

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.

Seguidamente, se especifica GROUP BY nombre_equipo. Al hacer esta agrupación, lo que


se hace es que cuando el nombre del equipo es igual, se compacta en una fila.

SELECT COUNT(DNI), nombre_equipo FROM jugador GROUP BY nombre_equipo;


Print output:

SUM()

La función SUM() devuelve la suma total de una columna numérica.

En el siguiente ejemplo, se suma el valor de los dorsales por equipo.

• Barcelona tiene dos dorsales, el 1 y el 9, por lo que el resultado ha de ser 10.


• Madrid tiene un dorsal, el 2, por lo que el resultado ha de ser 2.

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.

Seguidamente, se especifica GROUP BY nombre_equipo. Se escoge el atributo


nombre_equipo porque se están sumando valores de dorsales por equipo. Al hacer esta
agrupación, lo que se hace es que cuando el nombre del equipo es igual, se compacta en una
fila.

SELECT SUM(dorsal), nombre_equipo FROM jugador GROUP BY nombre_equipo;


Print output:

MIN()

La función MIN() devuelve el valor más pequeño de la columna seleccionada.

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.

Seguidamente, se especifica GROUP BY nombre_equipo. Al hacer esta agrupación, lo que


se hace es que cuando el nombre del equipo es igual, se compacta en una fila.

SELECT MIN(dorsal), nombre_equipo FROM equipo GROUP BY nombre_equipo;


Print output (para cada nombre de equipo distinto que haya, se mira cuál es el valor mínimo del
dorsal y se muestra):

Página 32 de 113
MAX()

La función MAX() devuelve el valor mayor/más alto de la columna seleccionada.

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.

Seguidamente, se especifica GROUP BY nombre_equipo. Al hacer esta agrupación, lo que


se hace es que cuando el nombre del equipo es igual, se compacta en una fila.

SELECT MAX(dorsal), nombre_equipo FROM equipo GROUP BY nombre_equipo;


Print output (para cada nombre de equipo distinto que haya, se mira cuál es el valor más alto
del dorsal y se muestra):

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

SELECT AVG(presupuesto) FROM equipo;


Print output:

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.

• A recordar: el alias de la tabla Estudia es e, mientras que el alias de la tabla Asignatura


es as.

Dentro del WHERE, se relacionan las tablas Estudia y Asignatura por medio del atributo
id_asignatura: WHERE e.id_asignatura = as.id_asignatura

Se agrupa por id_asignatura, con GROUP BY as.id_asignatura

Finalmente, se comprueba el valor de la media con HAVING: HAVING AVG(nota) > 5

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:

SELECT AVG(nota), as.nombre FROM estudia AS e, asignatura AS as


WHERE e.id_asignatura = as.id_asignatura
GROUP BY as.id_asignatura
HAVING AVG(nota) > 5

Otro ejemplo: media de las notas de las asignaturas con una id entre 1 y 5.

Primero se selecciona —SELECT— la media de las notas —AVG(nota)— y se muestra 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—.

• A recordar: el alias de la tabla Estudia es e, mientras que el alias de la tabla Asignatura


es as.

Dentro del WHERE, se relacionan las tablas Estudia y Asignatura por medio del atributo
id_asignatura: WHERE e.id_asignatura = as.id_asignatura

Se agrupa por id_asignatura, con GROUP BY 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:

SELECT AVG(nota), as.nombre FROM estudia AS e, asignatura AS as


WHERE e.id_asignatura = as.id_asignatura
GROUP BY as.id_asignatura
HAVING as.id_asignatura BETWEEN 1 AND 5

Otro ejemplo: Media de las notas de las asignaturas siempre que esta sea superior a 5 y con
una id entre 1 y 5.

De la misma manera que en el HAVING podemos aplicar funciones de agregación y operadores


de comparación, también se pueden utilizar operadores lógicos, como el AND y el OR.

En este ejemplo, tenemos dos condiciones: que la nota sea superior a 5 y (AND) que la
id_asignatura esté entre 1 y 5.

Primero se selecciona —SELECT— la media de las notas —AVG(nota)— y se muestra 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—.

• A recordar: el alias de la tabla Estudia es e, mientras que el alias de la tabla Asignatura


es as.

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

Se agrupa por id_asignatura, con GROUP BY 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:

SELECT AVG(nota), as.nombre FROM estudia AS e, asignatura AS as


WHERE e.id_asignatura = as.id_asignatura
GROUP BY as.id_asignatura
HAVING AVG(nota) > 5 AND as.id_asignatura BETWEEN 1 AND 5

ICA0002-S2-C2-V3 Order by y Limit


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102404)

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

La palabra clave o keyword ORDER BY se utiliza para ordenar el conjunto de resultados en


orden ascendente (por defecto) o descendente.

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

Primeramente, se selecciona el nombre y el dorsal, que es lo que se desea mostrar —SELECT


nombre, dorsal—, de la tabla Jugador —FROM jugador— y se indica que se ordene de
forma ascendente de acuerdo a los dorsales —ORDER BY dorsal—. No obstante, también
se puede indicar explícitamente este orden ascendente —ORDER BY dorsal ASC—.

SELECT nombre, dorsal FROM jugador ORDER BY dorsal;

SELECT nombre, dorsal FROM jugador ORDER BY dorsal ASC;


Print output:

Página 37 de 113
Ejemplo: Selecciona el nombre y dorsal de los jugadores y ordena según su dorsal de forma
descendente

Primeramente, se selecciona el nombre y el dorsal, que es lo que se desea mostrar —SELECT


nombre, dorsal—, de la tabla Jugador —FROM jugador— y se indica que se ordene de
forma descendente de acuerdo a los dorsales —ORDER BY dorsal DESC—.

SELECT nombre, dorsal FROM jugador ORDER BY dorsal DESC;


Print output:

Además de ordenar números, con ORDER BY se pueden ordenar cadenas de texto:

• La ordenación ascendente ordena de A-Z

• La ordenación descendente de Z-A.

Ejemplo: Selecciona el nombre y ordena según el nombre de los jugadores de la A a la Z


(ascendente).

Puede hacerse de dos maneras:

SELECT nombre FROM jugador ORDER BY nombre;

SELECT nombre FROM jugador ORDER BY nombre ASC;


Print output:

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:

SELECT nombre, apellido FROM jugador ORDER BY apellido DESC, nombre


ASC;
Print output:

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.

LIMIT limita el número de registros.

Ejemplo: Selecciona el nombre y apellido de un jugador.

El enunciado dice claramente que se ha de seleccionar el nombre y apellido de un único jugador.


Por tanto, hay que limitar el registro que aparezca. Para ello, se utiliza la función LIMIT.

SELECT nombre, apellido FROM jugador LIMIT 1;

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

SELECT nombre, apellido FROM jugador ORDER BY dorsal ASC LIMIT 1;

LIMIT OFFSET (SE RECONOCE PORQUE LIMIT TIENE DOS PARÁMETROS)

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)».

En este ejemplo, primero el dorsal se ordena de forma ascendente —ORDER BY dorsal


ASC— y, seguidamente, se especifica LIMIT 2,1, estableciendo así que se ha de mostrar el
tercer resultado.

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)

Un conjunto es una agrupación de valores. Cuando tenemos distintas agrupaciones, podemos


operar entre ellas. Las tres operaciones básicas de los conjuntos son la unión (UNION), la
intersección (INTERSEC) y la diferencia (MINUS).

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.

(SELECT nombre_equipo FROM equipo WHERE ano_fundacion < 1900)


UNION
(SELECT nombre_equipo FROM equipo WHERE ano_fundacion > 2000)

Página 41 de 113
INTERSEC

A nivel de MySQL no está implementado; por tanto, solo se aprenderá teóricamente.

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.

(SELECT nombre_equipo FROM equipo WHERE ano_fundacion < 1900)


INTERSEC
(SELECT nombre_equipo FROM equipo WHERE presupuesto > 1000000)
Resultado a obtener: los nombres de equipo que estén presentes en las dos selecciones.

MINUS

MINUS también se conoce como la resta. No se puede implementar de forma práctica en


MySQL, pero se va a aprender de forma teórica.

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.

(SELECT nombre_equipo FROM equipo WHERE ano_fundacion < 1900)


MINUS
(SELECT nombre_equipo FROM equipo WHERE presupuesto > 3500000)
Resultado a obtener: todos los resultados que estén en el primer SELECT (es decir, aquellos
fundados antes del año 1900), PERO que no tengan un presupuesto mayor a 3500000.

ICA0002-S03-C01

ICA0002-S3-C1-V1 Creación de la Base de Datos


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102411)

CREATE DATABASE

¿Cómo se crea una base de datos? Hay dos alternativas:


CREATE DATABASE nombre_de_la_base_de_datos → CREATE DATABASE
ejercicio1;

Si se desea crear una base de datos SIEMPRE Y CUANDO NO EXISTA YA:


CREATE DATABASE IF NOT EXISTS nombre_de_la_base_de_datos → CREATE
DATABASE ejercicio1;

USE

Una vez creada la base de datos, si se quiere utilizar se usa el comando USE.

USE nombre_de_la_base_de_datos → USE ejercicio1 → uso o acceso a la BB.


DD. ejercicio1.

CHARACTER SET o JUEGO DE CARACTERES

Un aspecto muy importante dentro de la base de datos es el juego de caracteres. El juego de


caracteres es el que permite codificar la información y guardar los distintos símbolos dentro de
nuestras tablas, dentro de nuestros atributos.

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.

• COMPAGINACIÓN BIN (BINARY): Compara los distintos caracteres a través de su


posición en el juego de caracteres.

• COMPAGINACIÓN CASE INSENSITIVE: No hace diferencia entre mayúsculas y


minúsculas. Las letras a A son la misma letra.

• COMPAGINACIÓN CASE SENSITIVE: Sí que hace diferencia entre mayúsculas y


minúsculas. Las letras a A son diferentes.

SHOW

Para mostrar los juegos de caracteres que tenemos dentro del sistema, dentro de MySQL, se usa
la herramienta SHOW.

Muestra todos los juegos de caracteres:

SHOW CHARACTER SET;

Muestra todas las compaginaciones de todos los juegos de caracteres:

SHOW COLLATION;

Muestra todas las compaginaciones de un juego de caracteres concreto (por ejemplo, latín 1):

SHOW COLLATION LIKE ‘latin1%’

Las compaginaciones más habituales que podemos encontrar con latín 1 son:

➔ latin1_swedish_ci (por defecto) Nótese que ci es case insensitive.


➔ latin1_bin Nótese que bin es binary.
➔ latin1_general_ci Nótese que ci es case insensitive
➔ latin1_general_cs Nótese que cs es case sensitive
➔ latin1_spanish_ci Nótese que ci es case insensitive

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:

CREATE DABATASE ejercicio1 DEFAULT CHARACTER SET ‘utf8’ DEFAULT


COLLATE ‘utf8_bin’;

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:

CREATE DATABASE IF NOT EXISTS ejercicio1 DEFAULT CHARACTER SET ‘utf8’


DEFAULT COLLATE ‘utf8_spanish_ci’;

Codificación HTML (juegos de caracteres) / HTML Encoding (Character Sets)

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! $ + - () @ <>.

La especificación HTML5 anima a los desarrolladores web a utilizar el juego de caracteres


UTF-8, que cubre casi todos los caracteres y símbolos del mundo.

COLLATION O COMPAGINACIÓN

Un juego de caracteres determinado siempre tiene al menos una compaginación, y la


mayoría de los juegos de caracteres tienen varias.

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.

Primeramente, se pone la declaración SQL CREATE TABLE nombre_de_la_tabla y se


abre un paréntesis (. En este caso, CREATE TABLE equipo(

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),

Data Types Descripción


VARCHAR(size) Una cadena de caracteres de longitud
VARIABLE (puede contener letras, números y
caracteres especiales). El parámetro size
especifica la longitud máxima de la columna
en caracteres, que puede ser de 0 a 65535.
DECIMAL(size, d) Un número de punto fijo exacto. El número
total de dígitos se especifica en size. El
número de dígitos después del punto decimal
se especifica en el parámetro d. El número
máximo para size es 65. El número máximo
para d es 30. El valor por defecto para size es
10. El valor por defecto para d es 0.
INT(size) Un entero medio. El rango con signo es de
-2147483648 a 2147483647. El rango sin
signo es de 0 a 4294967295. El parámetro size
especifica la anchura máxima de visualización
(que es de 255).

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.

**La diferencia entre VARCHAR(size) y CHAR(size) es que CHAR(size) es


FIJO/ESTÁTICO, lo que significa que, a nivel de memoria, un CHAR(3) siempre ocupará la
memoria específica para esos tres caracteres, aunque estén vacíos.

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.

Seguidamente, se estipula la clave primaria y el atributo; en este caso PRIMARY KEY


(nombre_equipo). Esto es una restricción (SQL PRIMARY KEY Constraint) que se explicará
más adelante.

Se cierra con );

Código completo de creación de la tabla de equipo:

CREATE TABLE equipo(


nombre_equipo VARCHAR(20),
presupuesto DECIMAL,
ano_fundacion INT,
es_federado BOOLEAN,
fecha_proximo_partido DATE,
momento_ultima_expulsion DATETIME,
siglas CHAR(3),
PRIMARY KEY(nombre_equipo)
);

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,

Por tanto, dada esta tabla:

La creación de la misma mediante código, utilizando CREATE TABLE IF NOT EXISTS,


quedaría tal que así:

CREATE TABLE IF NOT EXISTS equipo(


nombre_equipo VARCHAR(20),
presupuesto DECIMAL,
ano_fundacion INT,
es_federado BOOLEAN,
fecha_proximo_partido DATE,
momento_ultima_expulsion DATETIME,
siglas CHAR(3),
PRIMARY KEY(nombre_equipo)
);

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

A nivel de restricciones, se pueden identificar 4 restricciones diferentes dentro de SQL:

➔ PK: Restricciones de Clave Primaria (SQL PRIMARY KEY Constraint).


https://www.w3schools.com/sql/sql_primarykey.asp
➔ FK: Restricciones de Clave Forana (SQL FOREIGN KEY Constraint).
https://www.w3schools.com/sql/sql_foreignkey.asp
➔ Restricciones de tipo UNIQUE (SQL UNIQUE Constraint).
https://www.w3schools.com/sql/sql_unique.asp
➔ Restricciones de tipo CHECK (SQL CHECK Constraint) (no funcionan en MySQL).
https://www.w3schools.com/sql/sql_check.asp

Restricción / Constraint Descripción


SQL PRIMARY KEY Constraint La restricción PRIMARY KEY identifica de
forma exclusiva cada registro de una tabla.

Las claves primarias deben contener valores


UNIQUE y no pueden contener valores
NULL.

Una tabla sólo puede tener UNA clave


primaria; y en la tabla, esta clave primaria
puede constar de una o varias columnas
(campos).
SQL FOREIGN KEY Constraint La restricción FOREIGN KEY se utiliza para
evitar acciones que destruyan los vínculos
entre tablas.

Una FOREIGN KEY (FK) es un campo (o


conjunto de campos) de una tabla que hace
referencia a la PRIMARY KEY (PK) de otra
tabla.

La tabla con la Foreign Key (FK) se llama tabla


hija («child table»), y la tabla con la Primary
Key se llama tabla referenciada o matriz
(«referenced or parent table»).
SQL UNIQUE Constraint La restricción UNIQUE garantiza que todos
los valores de una columna son diferentes.

Tanto la restricción UNIQUE como la


PRIMARY KEY garantizan la unicidad
(cualidad de único) de una columna o
conjunto de columnas.

Página 49 de 113
Una restricción PRIMARY KEY tiene
automáticamente una restricción UNIQUE.

Sin embargo, puede tener muchas


restricciones UNIQUE por tabla, pero sólo
una restricción PRIMARY KEY por tabla.
SQL CHECK Constraint La restricción CHECK se utiliza para limitar el
rango de valores que se pueden colocar en
una columna.

Si se define una restricción CHECK en una


columna, solo se permitirán ciertos valores
para esta columna.

Si se define una restricción CHECK en una


tabla, puede limitar los valores de ciertas
columnas basándose en los valores de otras
columnas de la fila.

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.

A continuación, se adjunta la creación de la tabla Alumno de dos maneras distintas, según se


hayan especificado las restricciones de una forma u otra.

Las restricciones se pueden crear de dos maneras distintas:

Indicando la cláusula CONSTRAINT con un nombre que definimos nosotros mismos y


que debe ser único para toda la base de datos (no solo para la tabla). Viene a ser como
un alias que ayuda a identificar la restricción

En el código superior izquierdo se ha hecho CONSTRAINT pk_alumno PRIMARY


KEY(DNI). pk_alumno es el nombre dado a esta restricción, mientras que DNI es el
atributo PK. Por su parte, para la restricción del mail se hace lo mismo: CONSTRAINT
u_mail UNIQUE(mail). u_mail es el nombre dado a esta restricción, mientras que
mail es el atributo; así se indica que el mail es único.

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

Para crear la tabla Estudia se ha optado por el siguiente código:

Primero de todo tenemos tres atributos: DNI, id_asignatura y nota.

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:

CONSTRAINT pk_estudia PRIMARY KEY(DNI, id_asignatura),

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

Quedando tal que así (definición de FK de la tabla Estudia):

CONSTRAINT fk_alumno FOREIGN KEY(DNI) REFERENCES alumno(DNI),


CONSTRAINT fk_asignatura FOREIGN KEY(id_asignatura) REFERENCES
asignatura(id_asignatura)

*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

El valor de un atributo autoincremental (AUTO_INCREMENT) se va incrementando


secuencialmente 1, 2, 3…

El valor inicial de un valor autoincremental (AUTO_INCREMENT) es 1, y se le va sumando 1


cada nuevo registro grabado en la tabla. No obstante, podemos darle un valor concreto, siempre
que este valor no exista.

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

Código de creación de la tabla Asignatura con AUTO_INCREMENT:

CREATE TABLE asignatura(


id_asignatura INT AUTO_INCREMENT,
nombre VARCHAR(20),
descripcion VARCHAR(200),
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

NOT NULL

Con la propiedad NOT NULL se estipula que un atributo de una tabla nunca será NULL.

En el siguiente ejemplo se establece que no se podrá ninguna asignatura sin nombre:

Código de creación de la tabla Asignatura con NOT NULL:

CREATE TABLE asignatura(


id_asignatura INT,
nombre VARCHAR(20) NOT NULL,
descripcion VARCHAR(200),
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

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.

En el siguiente ejemplo la descripción por defecto, si no le asignamos un valor concreto, será


Texto por defecto.

Código de creación de la tabla Asignatura con DEFAULT:

CREATE TABLE asignatura(


id_asignatura INT,
nombre VARCHAR(20),
descripcion VARCHAR(200) DEFAULT ‘Texto por defecto’,
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

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.

Código de creación de la tabla Asignatura con UNSIGNED:

CREATE TABLE asignatura(


id_asignatura INT UNSIGNED,
nombre VARCHAR(20),
descripcion VARCHAR(200),
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

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.

Código de creación de la tabla Asignatura con ZEROFILL:

CREATE TABLE asignatura(


id_asignatura INT ZEROFILL,
nombre VARCHAR(20),
descripcion VARCHAR(200),
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

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.

CHARACTER SET O JUEGO DE CARACTERES

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.

CREATE TABLE asignatura(


id_asignatura INT,
nombre VARCHAR(20) CHARACTER SET ‘utf8’ COLLATE ‘utf8_bin’,
descripcion VARCHAR(200),
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
) CHARACTER SET ‘utf8’ COLLATE ‘utf8_general_cs’;

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.

Código de creación de la tabla Asignatura con COMMENT:

CREATE TABLE asignatura(


id_asignatura INT,
nombre VARCHAR(20),
descripcion VARCHAR(200) COMMENT ‘Esto es un comentario’,
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

MÚLTIPLES PROPIEDADES

Un atributo puede tener más de una propiedad.

En el siguiente ejemplo, tenemos un campo que es autoincremental (AUTO_INCREMENT) y


que, además, no puede ser NULL (NOT NULL). Está definido, pues, con las dos propiedades.
No obstante, en este caso, puesto que id_asignatura también es la PK, por defecto ya tampoco
puede ser NULL.

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:

CREATE TABLE asignatura(


id_asignatura INT AUTO_INCREMENT NOT NULL,
nombre VARCHAR(20),
descripcion VARCHAR(200),
CONSTRAINT pk_asignatura PRIMARY KEY(id_asignatura)
);

¿Cómo se puede ver el código de creación de una tabla una vez ejecutada?

Con el comando SHOW CREATE TABLE nombre_de_la_tabla;

Por ejemplo:

SHOW CREATE TABLE asignatura;

ICA0002-S3-C1-V4 Alteración de las tablas


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102414)

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.

ADD PRIMARY KEY

Supongamos que en la tabla Asignatura no se ha especificado una Clave Primaria. Para


solventarlo, hay que modificarla con la herramienta ALTER TABLE.

• 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—.

La declaración para añadir la PK a la tabla Asignatura sería:

ALTER TABLE nombre_de_la_tabla_a_modificar ADD CONSTRAINT


nombre_de_la_constraint PRIMARY
KEY(atributo_ya_existente_en_la_tabla_que_se_asigna_como_PK);

Quedaría así:

ALTER TABLE asignatura ADD CONSTRAINT pk_asignatura PRIMARY


KEY(id_asignatura);
De este modo, el atributo id_asignatura sería PK en la tabla Asignatura.

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

La declaración para añadir la PK compuesta a la tabla sería:

ALTER TABLE nombre_de_la_tabla_a_modificar ADD CONSTRAINT


nombre_de_la_constraint PRIMARY KEY
(atributo1_ya_existente_en_la_tabla_que_se_asigna_como_PK,
atributo2_ya_existente_en_la_tabla_que_se_asigna_como_PK);

Página 58 de 113
Quedaría así:

ALTER TABLE estudia ADD CONSTRAINT pk_estudia PRIMARY KEY(DNI,


id_asignatura);

ADD FOREIGN KEY

La declaración para añadir la FK a la tabla sería:

ALTER TABLE nombre_de_la_tabla_a_modificar ADD CONSTRAINT


nombre_de_la_constraint FOREIGN KEY
(atributo_ya_existente_en_la_tabla_que_se_asigna_como_FK) REFERENCES
tabla_a_la_que_se_vincula(PK_de_la_tabla_a_la_que_se_vincula);

Para añadir la FK id_asignatura a la tabla Estudia, la declaración quedaría así:

ALTER TABLE estudia ADD CONSTRAINT fk_asignatura FOREIGN KEY


(id_asignatura) REFERENCES asignatura(id_asignatura);

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.

SQL UPDATE Statement La sentencia UPDATE se utiliza para


modificar los registros existentes en una
tabla.
SQL DELETE Statement La sentencia DELETE se utiliza para eliminar
los registros existentes en una tabla.

UPDATE CASCADE / ACTUALIZAR Cuando se crea una Clave Forana FK


CASCADA utilizando UPDATE CASCADE, las filas de
referencia se van a actualizar en la tabla
secundaria cuando la fila referenciada se
actualiza en la tabla principal que tiene una
Clave Primaria PK.
DELETE CASCADE / ELIMINAR EN Cuando se crea una Clave Forana FK
CASCADA utilizando DELETE CASCADE, elimina las
filas de referencia en la tabla secundaria
cuando la fila referenciada se elimina en la
tabla primaria que tiene una Clave Primaria
PK.

Página 59 de 113
Código para añadir la FK id_asignatura con comportamiento de UPDATE y DELETE:

ALTER TABLE nombre_de_la_tabla_a_modificar ADD CONSTRAINT


nombre_de_la_constraint FOREIGN KEY
(atributo_ya_existente_en_la_tabla_que_se_asigna_como_FK) REFERENCES
tabla_a_la_que_se_vincula(PK_de_la_tabla_a_la_que_se_vincula) ON
UPDATE CASCADE ON DELETE CASCADE;

ALTER TABLE estudia ADD CONSTRAINT fk_asignatura FOREIGN KEY


(id_asignatura) REFERENCES asignatura(id_asignatura) ON UPDATE CASCADE
ON DELETE CASCADE;

Restricciones de clave externa o Foreign Key Constraints


(https://es.stackoverflow.com/questions/105890/qu%C3%A9-significa-cascade-set-null-
restrict-no-action-en-mysql /
https://web.archive.org/web/20210402171910/https://es.stackoverflow.com/questions/10
5890/qu%C3%A9-significa-cascade-set-null-restrict-no-action-en-mysql).

Con ellas, la propia base de datos impide que se realicen operaciones que provocarían
inconsistencias.

El comportamiento por defecto de una restricción de clave externa es impedir un cambio en la


base de datos como consecuencia de una sentencia DELETE o UPDATE, si esta trajese como
consecuencia un fallo de la integridad referencial.

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.

ADD FOREIGN KEY MULTIPLE

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:

ALTER TABLE nombre_de_la_tabla_a_modificar ADD CONSTRAINT


nombre_de_la_constraint PRIMARY KEY
(atributo1_ya_existente_en_la_tabla_que_se_asigna_como_PK,
atributo2_ya_existente_en_la_tabla_que_se_asigna_como_PK);

Respecto a la Clave Forana (FK) compuesta, se hace de forma similar:

ALTER TABLE nombre_de_la_tabla_a_modificar ADD CONSTRAINT


nombre_de_la_constraint FOREIG KEY
(atributo_1_que_forme_parte_de_la_clave_multiple,
atributo_2_que_forme_parte_de_la_clave_multiple) REFERENCES
tabla_a_la_que_se_hace_referencia (atributo_1_al_que_se_hace_referenci
a, atributo_2_al_que_se_hace_referencia);

Ejemplo: Añadir la FK múltiple de la tabla Hospital_Medico:

ALTER TABLE hospital_medico ADD CONSTRAINT fk_hospital_medico FOREIGN


KEY (nombre, pais) REFERENCES hospital (nombre, pais);

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.

DROP PRIMARY KEY / DROP FOREIGN KEY

ALTER TABLE también permite borrar PK y FK.

Página 61 de 113
Para borrar la PK de una tabla:

ALTER TABLE nombre_de_la_tabla_a_la_que_se_quiere_borrar_la_PK DROP


PRIMARY KEY;

Ejemplo: Para borrar la PK de la tabla Asignatura:

ALTER TABLE asignatura DROP PRIMARY KEY;

Para borrar la FK de una tabla:

ALTER TABLE nombre_de_la_tabla_a_la_que_se_quiere_borrar_la_FK DROP


FOREIGN KEY nombre_que_se_le_ha_dado_a_la_CONSTRAINT

Ejemplo: Para borrar la FK id_asignatura de la tabla Estudia:

ALTER TABLE estudia DROP FOREIGN KEY fk_asignatura;

ADD/DROP FIELD

ALTER TABLE también permite añadir o borrar campos (atributos) a una tabla.

Añadir un campo para un atributo:

ALTER TABLE nombre_de_la_tabla ADD nombre_del_atributo


tipo_de_dato_del_atributo;

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.

ALTER TABLE asignatura ADD créditos INT;

Borrar el campo de un atributo:

ALTER TABLE nombre_de_la_tabla DROP nombre_del_atributo;

Ejemplo: en la tabla Asignatura se quiere borrar el atributo creditos:

ALTER TABLE asignatura DROP creditos;

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.

Ejemplo: Cambiar el tipo de campo de la descripción de Asignatura a TEXT —puesto que es un


VARCHAR(size)—:

ALTER TABLE nombre_de_la_tabla MODIFY atributo_a_cambiar


nuevo_SQL_data_type

ALTER TABLE asignatura MODIFY description TEXT;

Ejemplo: Cambiar el tipo de campo de la descripción de Asignatura a TEXT, indicando que no


puede ser NULL (con SQL NOT NULL Constraint: Por defecto, una columna puede contener
valores NULL. La restricción NOT NULL obliga a una columna a NO aceptar valores NULL. Esto
obliga a un campo a contener siempre un valor):

ALTER TABLE nombre_de_la_tabla MODIFY atributo_a_cambiar


nuevo_SQL_data_type NOT NULL;

ALTER TABLE asignatura MODIFY description TEXT NOT NULL;

CHANGE

CHANGE se utiliza para cambiar el nombre de un atributo.

ALTER TABLE nombre_de_la_tabla CHANGE nombre_del_atributo_a_cambiar


nuevo_nombre SQL_data_type;
Ejemplo: Cambiar el atributo nombre de la tabla Asignatura por nombre_asignatura:

ALTER TABLE asignatura CHANGE nombre_asignatura VARCHAR(50);

Página 63 de 113
ICA0002-S3-C1-V5 Renombrado, borrado y vistas
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102415)

RENAME

Para cambiar una tabla de nombre pueden escogerse dos formas:

• Con el comando RENAME TABLE … TO


RENAME TABLE nombre_de_la_tabla_a_cambiar TO
nuevo_nombre_de_la_tabla;

• Con el comando ALTER TABLE … RENAME AS


ALTER TABLE nombre_de_la_tabla_a_cambiar RENAME AS
nuevo_nombre_de_la_tabla;

Ejemplo: Cambio del nombre de la tabla estudia a alumno_asignatura:

RENAME TABLE estudia TO alumno_asignatura;

ALTER TABLE estudia RENAME AS alumno_asignatura;

DROP TABLE

DROP TABLE sirve para borrar una tabla.

Borrar una tabla:

DROP TABLE nombre_de_la_tabla_a_borrar;

Página 64 de 113
Borrar una tabla comprobando antes si existe o no (si se elimina sin existir el sistema dará
error):

DROP TABLE IF EXISTS nombre_de_la_tabla_a_eliminar;

Ejemplo: Borrado de la tabla estudia:

DROP TABLE estudia;

Ejemplo: Borrado de la tabla estudia si existe:

DROP TABLE IF EXISTS estudia;

DROP DATABASE

DROP DATABASE sirve para borrar una base de datos. Hay que utilizarlo con precaución.

Borrar una base de datos:

DROP DATABASE nombre_de_la_base_de_datos_a_eliminar;

Borrar una base de datos comprobando antes si existe o no:

DROP DATABASE IF EXISTS nombre_de_la_base_de_datos_a_eliminar;

Ejemplo: Borrar la base de datos ejercicio1:

DROP DATABASE ejercicio1;

Ejemplo: Borrar la base de datos ejercicio1 si existe:

DROP DATABASE IF EXISTS ejercicio1;

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:

CREATE VIEW nombre_de_la_vista AS SELECT registro1_a_recuperar,


registro2_a_recuperar FROM nombre_de_la_tabla;

Ejemplo: Crear una vista de los nombres y apellidos de los alumnos:

CREATE VIEW vista1 AS SELECT nombre, apellido FROM alumno;

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:

CREATE OR REPLACE VIEW nombre_de_la_vista AS SELECT


registro1_a_recuperar, registro2_a_recuperar FROM nombre_de_la_tabla;

Ejemplo: Crear una vista o reemplazarla si existe de los nombres y apellidos de los alumnos:

CREATE OR REPLACE VIEW vista1 AS SELECT nombre, apellido FROM alumno;

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.

Para mostrar todo el contenido de una vista:

SELECT * FROM nombre_de_la_vista;

Ejemplo: Mostrar la vista1:

SELECT * FROM vista1;

Página 66 de 113
Para mostrar solo una columna:

SELECT nombre_de_la_columna FROM nombre_de_la_vista;

Ejemplo: Mostrar los nombres de la vista1:

SELECT nombre FROM vista1;

Se acepta cualquier tipo de operación que tengamos en una selección: ordenar los datos,
filtrarlos, etc.

DROP VIEW

DROP VIEW sirve para borrar una vista.

Ejemplo: Borrar la vista1:

DROP VIEW vista1;

Ejemplo: Borrar la vista1 si existe:

DROP VIEW IF EXISTS vista1;

ICA0002-S3-C1-V6 Ejemplos de crear, alterar, renombrar y borrar estructuras en XAMPP


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102416)

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

En este punto, se crea una base de datos mediante código:

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:

DROP TABLE federacion;

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:

DROP TABLE equipo;

DROP TABLE federacion;

Página 70 de 113
ICA0002-S03-C02

ICA0002-S3-C2-V1 Inserción de Datos


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102421)

Partiremos de la tabla Equipo, con su PK nombre_equipo y sus atributos.

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 INTO equipo VALUES (‘Barcelona’, 3000000, 1899, TRUE, ‘2019-03-


02’, ‘2018-11-10 21:03:27’, ‘FCB’);

INSERT INTO equipo VALUES (‘Sporting La Salle’, 5000, 2015, FALSE,


‘2019-03-20’, ‘2018-10-8 15:30:48’, ‘SLS’);

Sobre los valores, nótese que:

• Cuando son cadenas de caracteres van entre comillas simples ‘ ’.


• Las fechas (DATE) y fechas con horas (DATETIME) también van entre comillas simples
‘ ’.
• Cuando son números, no van entre comillas.
• Cuando son tipos booleanos —TRUE FALSE— tampoco van entre comillas.
• El tipo NULL tampoco iría entre comillas.

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.

INSERT INFO equipo (nombre_equipo, presupuesto, siglas) VALUES


(‘Madrid’, 4000000, ‘RMA’);

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.

INSERT con FK’s

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

Creación del equipo Sporting La Salle:

INSERT INFO equipo VALUES (‘Sporting La Salle’, 5000, 2000);

Creación del jugador, definiendo en su FK nombre_equipo el equipo en el juega (Sporting La


Salle):

INSERT INFO jugador (DNI, nombre, apellido, nombre_equipo) VALUES


(‘2222222B’, ‘Juan’, ‘García’, ‘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.

INSERT INTO jugador (DNI, nombre, apellido, nombre_equipo) VALUES


(‘3333333C’, ‘David’, ‘López’, NULL);

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.

❌En el siguiente ejemplo, el equipo «Sevilla» no existe. Por tanto, es incorrecto: ❌

INSERT INTO jugador (DNI, nombre, apellido, nombre_equipo) VALUES


(‘4444444D’, ‘Manuel’, ‘Expósito’, ‘Sevilla’);

A continuación, se va a utilizar el esquema inferior, conformado por tres tablas: Alumno, Estudia
y Asignatura.

INSERT con PK-FK’s

INSERT con PK-FK’s es similar al INSERT con FK’s.

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.

En el caso de que el alumno o la asignatura no estén creados en las tablas de origen


correspondientes, se producirá un error.

Así, primero se crea el alumno en la tabla Alumno:

INSERT INTO alumno VALUES (‘1111111A’, ‘Paco’, ‘Pérez’, ‘Gutiérrez’,


TRUE, ‘2000-07-22’);

Seguidamente, se crea la asignatura en la tabla Asignatura:

INSERT INTO asignatura VALUES (1, ‘Bases de Datos’, NULL);

Luego se hace el INSERT con PK-FK’s:

INSERT INTO estudia VALUES (‘1111111A’, 1, 7);

❌¿Qué pasa si en id_asignatura de la tabla Estudia trata de ponerse un id que no se ha creado


—como 2—? Que se produce un error: ❌

INSERT INTO estudia VALUES (‘1111111A’, 2, 7);

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:

INSERT INTO asignatura VALUES (2, ‘Sistemas’, NULL);

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:

INSERT INTO asignatura VALUES (NULL, ‘Sistemas’, NULL);

Si insertamos comillas simples vacías ‘ ’ en el campo id_asignatura, el sistema también


generará un valor autoincremental:

INSERT INTO asignatura VALUES (‘ ’, ‘JAVA’, NULL);

En el caso de hacer un INSERT Indirecto, si no se define el campo id_asignatura, como es


autoincremental, aunque sea PK y es obligatorio, y no lo tengamos definido, el propio sistema
se encargará de dar un valor a id_asignatura:

INSERT INTO asignatura (nombre, descripcion) VALUES (‘XML’, NULL);

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

ICA0002-S3-C2-V2 Modificación de Datos


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102422)

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.

Ejemplo: Respecto a la tabla Asignatura, se desea actualizar el nombre de la asignatura con


id:1 a BBDD. La sintaxis a seguir es la siguiente:

UPDATE asignatura SET nombre = ‘BBDD’ WHERE id_asignatura = 1;

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:

UPDATE alumno SET nombre = ‘Anna’, apellido = ‘Fernández’ WHERE DNI =


‘1111111A’;

✅ Con UPDATE se pueden usar las cláusulas ORDER BY y LIMIT. ✅

❌ Pero no se podrán utilizar nunca GROUP BY ni HAVING. ❌

Ejemplo: Actualizar la descripción de las 4 primeras asignaturas ordenando por id con el texto
‘Asignatura troncal’:

UPDATE asignatura SET descripcion = ‘Asignatura troncal’


ORDER BY id_asignatura ASC
LIMIT 4;

Cuando se pide borrar el contenido de un atributo, como es borrar el contenido de descripcion,


se sigue utilizando UPDATE, puesto que no es un borrado, es una modificación. Se modifica el
atributo y se pone a NULL.

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.

Ejemplo: Borrado de las descripciones de asignatura:

UPDATE asignatura SET descripcion = NULL;

ICA0002-S3-C2-V3 Borrado de datos


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102423)

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.

Borrar todos los datos de una tabla; quedaría la tabla vacía:

DELETE FROM nombre_de_la_tabla;

Página 76 de 113
Ejemplo: Borrar los datos de la tabla Alumno:

DELETE FROM 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 nombre_de_la_tabla WHERE elemento_concreto;

Ejemplo: Borrar el alumno con DNI 1111111A:

DELETE FROM alumno WHERE DNI = ‘1111111A’;

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 alumno


ORDER BY apellido ASC
LIMIT 4;

DELETE FROM: Entre DELETE y FROM no se pone nunca nada, ni asterisco ni nada.

ICA0002-S3-C2-V4 Ejemplos de insertar, modificar y borrar datos en XAMPP


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102424)

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.

Adicionalmente, se ejecuta la sentencia DELETE FROM clasificacion; , que borra dos


filas. Por ello, si se va a la visión general (pulsando sobre la base de datos en el menú izquierdo)
y se clica en «Estructura», se observa que clasificacion tiene 0 filas. Por su parte, federacion tiene
solo una fila.

ICA0002-S04-C01

ICA0002-S4-C1-V1 Introducción a las subconsultas


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102430)

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

Como se ve en el ejemplo superior, respecto a la base de datos Alumno, Estudia, Asignatura


tenemos una selección —SELECT— del nombre del alumno para mostrarlo —SELECT
nombre—. La nota ha de tener una condición; y esta condición se expresa a través de una
subconsulta.

¿Dónde pueden aparecer las subconsultas?

Dentro de una selección —SELECT—, las consultas pueden aparecer en tres sitios:

• Dentro del WHERE, como condición de un atributo.


• Dentro del HAVING, como condición de un grupo.
• Dentro del FROM (caso excepcional).

Página 78 de 113
¿Qué tipos de subconsultas hay?

• Subconsultas simples. Solo devuelven un valor; esto es, devuelven el valor de un


COUNT(), de un AVG(), de un MAX(), de un MIN(). O cualquier tipo de consulta que
devuelva única y exclusivamente un único valor.
• Subconsultas complejas. Pueden devolver más de un valor: o 0 o 1 o más de 1. En este
caso, las subconsultas se tratarán utilizando una serie de funciones. Las subconsultas
complejas siempre irán asociadas a una función:

o IN: Permite mirar si una cosa existe dentro de una lista.


o ANY: Permite mirar si una condición se cumple para cualquiera de las respuestas
de la subconsulta.
o ALL: Permite mirar si una subconsulta se cumple para todos los casos.
o EXISTS: Permite saber si para la subconsulta existe algún resultado o no.

ICA0002-S4-C1-V2 Subconsultas básicas


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102431)

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

Ejemplo: devuelve el DNI de los alumnos matriculados en dos asignaturas o más.

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:

o Alias para la tabla Alumno → a


o Alias para la tabla Estudia → e

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.

Función de agregación COUNT() en el HAVING: se cuentan cuántas asignaturas —esto es,


cuántos id_asignatura— tenemos, y en el caso de que sean igual o mayores a 2 —>= 2—,
queremos que nos devuelva el resultado. HAVING COUNT(e.id_asignatura) >= 2;.

Código completo:

SELECT a.DNI FROM alumno AS a, estudia AS e


WHERE a.DNI = e.DNI
GROUP BY a.DNI
HAVING COUNT(e.id_asignatura) >= 2;

Página 80 de 113
• Con subconsulta.

Hay que tener presente que se crea un ALIAS —AS— para las tablas:

o Alias para la tabla Alumno → a


o Alias para la tabla Estudia → e

En primer lugar, seleccionamos el DNI de la tabla Alumno. SELECT a.DNI FROM alumno
AS a.

Seguidamente, en WHERE introducimos la subconsulta. En este caso, hacemos una subconsulta


que nos cuente cuántas asignaturas tenemos por cada alumno. Por tanto, hacemos un SELECT
COUNT(e.id_asignatura) de la tabla Estudia —porque es la que se relaciona
directamente con Alumno, y contando directamente id’s de asignatura, id_asignatura, ya nos
vale— FROM estudia AS e.

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:

SELECT a.DNI FROM alumno AS a


WHERE (SELECT COUNT(e.id_asignatura) FROM estudia AS e WHERE e.DNI =
a.DNI) >= 2;

Ejemplo: Devuelve el DNI de los alumnos con la mayor nota registrada en cualquier asignatura:

Esto se puede hacer con subconsulta de la siguiente manera:

Hay que tener presente que se crea un ALIAS —AS— para las tablas:

o Alias para la tabla Alumno → a


o Alias para la tabla Estudia → e1
o Alias para la tabla Estudia (subconsulta) → e2

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:

SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1


WHERE a.DNI = e1.DNI AND e1.nota = (SELECT MAX(e2.nota) FROM estudia
AS e2);

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:

SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1


WHERE a.DNI = e1.DNI AND e1.nota = (SELECT MIN(e2.nota) FROM estudia
AS e2);

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.

o Alias para la tabla Empleado → e


o Alias para la tabla Proyecto_Empleado → p2

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

Primera subconsulta: empleados que trabajen en 0 proyectos.

A recordar: La función COUNT() devuelve el número de filas de la consulta, es decir, el


número de registros que cumplen una determinada condición.

WHERE
(SELECT COUNT(ID_proyecto) FROM Proyecto_Empleado AS p2
WHERE p2.DNI=e.DNI) = 0

WHERE p2.DNI=e.DNI → Cuando el DNI que miramos de la tabla Proyecto_Empleado sea


igual al DNI de la persona que yo quiera mostrar —de la tabla Empleado—. = 0 → Y en el caso
de que sea 0, se muestra dicha persona.

Segunda subconsulta: empleados que trabajen en 3 proyectos.

OR
(SELECT COUNT(ID_proyecto) FROM Proyecto_Empleado AS p2
WHERE p2.DNI=e.DNI) = 3

Para mostrar el resultado en orden descendente según el DNI:

ORDER BY e.DNI DESC;

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

Los ejemplos se basan en la siguiente base de datos:

Página 84 de 113
Operador SQL IN → El operador IN permite seleccionar múltiples valores en una cláusula
WHERE.

Ejemplo externo extraído de: http://sql.11sql.com/sql-in.htm

Ejemplo: Devuelve el DNI y nombre de los alumnos matriculados en alguna asignatura.

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

SELECT a.DNI, a.nombre FROM alumno AS a, estudia AS e


WHERE a.DNI = e.DNI
GROUP BY a.DNI;

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.

Ejemplo: Devuelve el DNI y nombre de los alumnos no matriculados en alguna asignatura.

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.

SELECT a.DNI, a.nombre FROM alumno AS a


WHERE a.DNI NOT IN (SELECT e.DNI FROM estudia AS e
WHERE e.DNI = a.DNI);

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.

SELECT a.DNI, a.nombre FROM alumno AS a


WHERE a.DNI IN (‘2222222B’, ‘3333333C’, ‘4444444’);

Ejemplo: Devuelve los nombres y primer apellido de alumnos que se repitan conjuntamente
en otro alumno.

Con la función de IN también se pueden mirar conjuntos o agrupaciones de atributos. En el


siguiente caso, se devuelven los nombres y apellidos de aquellos alumnos que se repitan

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.

SELECT a.nombre, a.apellido FROM alumno AS a


WHERE (a.nombre, a.apellido) IN (SELECT a2.nombre, a2.apellido FROM
alumno AS a2 WHERE a2.DNI <> a.DNI);

Los siguientes ejemplos se basan en esta base de datos:

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

o Alias para la tabla Proyecto → p1


o Alias para la tabla Proyecto_Empleado → pe
o Alias para la tabla Empleado → e
o Alias para la tabla Proyecto (segunda subconsulta) → p2
o Alias para la tabla Lugar_Departamento → l

Siempre se muestra el ID_proyecto y el nom_proyecto, ambos atributos de la tabla Proyecto, por


tanto, hago la siguiente selección:

SELECT p1.ID_proyecto, p1.nom_proyecto FROM Proyecto AS p1

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

La consulta INTERSECT devuelve los registros en la


zona de sombra azul. Estos son los registros que existen
tanto en DataSet1 y Dataset2.

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.

o Alias para la tabla alumno → a


o Alias para la tabla alumno (subconsulta) → a2

Página 88 de 113
Se selecciona el nombre de la tabla de alumno:

SELECT a.nombre FROM alumno AS a

Miramos que ese nombre esté en la lista de apellidos de la tabla de alumno:

WHERE a.nombre IN (SELECT a2.apellido FROM alumno AS a2);

Código completo:

SELECT a.nombre FROM alumno AS a


WHERE a.nombre IN (SELECT a2.apellido FROM alumno AS a2);

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.

o Alias para la tabla alumno → a


o Alias para la tabla alumno (subconsulta) → a2

Se selecciona el nombre de la tabla Alumno:

SELECT a.nombre FROM alumno AS a

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:

SELECT a.nombre FROM alumno AS a


WHERE a.nombre NOT IN (SELECT a2.apellido FROM alumno AS a2);

ICA0002-S4-C1-V4 Subconsultas ANY


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102433)

Los ejemplos se basan en la siguiente base de datos:

SQL ANY Operator:

• Devuelve un valor booleano como resultado.


• Devuelve TRUE si CUALQUIERA de los valores de la subconsulta cumple la condición.

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.

Si la subconsulta no devuelve filas, entonces ANY da FALSE incluso si expresión es nula.

Ejemplo: Devuelve el DNI de todos los alumnos excepto el/los más joven/es:

o Alias para la tabla alumno → a1


o Alias para la tabla alumno (subconsulta) → a2

SELECT a1.DNI FROM alumno AS a1


WHERE a1.fecha_nacimiento > ANY (SELECT a2.fecha_nacimiento alumno AS
a2.DNI<>a1.DNI);

Explicación del código. Primero seleccionamos el DNI de la tabla Alumno:

SELECT a1.DNI FROM alumno AS a1

Indicando —WHERE— que la fecha de nacimiento —a1.fecha_nacimiento— tiene que


ser mayor —>— a cualquier —ANY— (y aquí comienza la subconsulta) fecha de nacimiento que
tengamos en la tabla de alumno —SELECT a2.fecha_nacimiento alumno AS a2—,
obviando la propia del alumno en cuestión —a2.DNI<>a1.DNI—.

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.

Los siguientes ejemplos se basan en esta base de datos:

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:

SELECT e.DNI, e.sueldo FROM Empleado AS e

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:

SELECT e.DNI, e.sueldo FROM Empleado AS e


WHERE
e.sueldo < (SELECT MAX(e2.sueldo) FROM Empleado AS e2);

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.

• Subconsulta con ANY


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:

SELECT e.DNI, e.sueldo FROM Empleado AS e

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:

SELECT e.DNI, e.sueldo FROM Empleado AS e


WHERE
e.sueldo < ANY (SELECT e.sueldo FROM Empleado AS e2);

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.

ICA0002-S4-C1-V5 Subconsultas ALL


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102434)

Los ejemplos se basan en la siguiente base de datos:

Página 93 de 113
SQL ALL Operator

• Devuelve un valor booleano como resultado.


• Devuelve TRUE si TODOS los valores de la subconsulta cumplen la condición.
• Se utiliza con las sentencias SELECT, WHERE y HAVING.

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.

Si la subconsulta no devuelve ninguna fila, entonces ALL da TRUE.

Ejemplo: Devuelve el DNI del/de los alumno/s más mayor/es

o Alias para la tabla alumno → a1


o Alias para la tabla alumno (subconsulta) → a2

Primero se selecciona el DNI, que es lo que queremos mostrar, de la tabla Alumno:

SELECT a1.DNI FROM alumno AS a1

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:

o Alias para la tabla alumno → a


o Alias para la tabla estudia → e1
o Alias para la tabla estudia (subconsulta) → e2

Se selecciona el DNI con la función DISTINCT de la tabla Alumno; y la tabla Estudia, para saber
qué alumnos estudian qué asignaturas:

SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1

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:

SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1


WHERE a.DNI = e1.DNI AND e1.nota = (SELECT MAX(e2.nota) FROM estudia
AS e2);

• Subconsulta con ALL:


o Alias para la tabla alumno → a
o Alias para la tabla estudia → e1
o Alias para la tabla estudia (subconsulta) → e2

Se selecciona el DNI con la función DISTINCT de la tabla Alumno; y la tabla Estudia, para saber
qué alumnos estudian qué asignaturas:

SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1

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:

SELECT DISTINCT(a.DNI) FROM alumno AS a, estudia AS e1


WHERE a.DNI = e1.DNI AND e1.nota >= ALL (SELECT e2.nota FROM estudia
AS e2);

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.

o Alias para la tabla Empleado → e


o Alias para la tabla Empleado (subconsulta) → e2

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.

Seleccionamos, con el fin de mostrarlos, el DNI y el sueldo de la tabla Empleado:

SELECT e.DNI, e.sueldo FROM Empleado AS e

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

ICA0002-S4-C1-V6 Subconsultas EXISTS


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102435)

Los ejemplos se basan en la siguiente base de datos:

SQL EXISTS Operator

• El operador EXISTS se utiliza para comprobar la existencia de cualquier registro en una


subconsulta.

• El operador EXISTS devuelve TRUE si la subconsulta devuelve uno o más registros.

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.

SELECT a.DNI, a.nombre FROM alumno AS a, estudia AS e

Se relacionan las tablas a través del DNI:

WHERE a.DNI = e.DNI

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:

SELECT a.DNI, a.nombre FROM alumno AS a, estudia AS e


WHERE a.DNI = e.DNI
GROUP BY a.DNI;

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

o Alias para la tabla alumno → a


o Alias para la tabla estudia (subconsulta) → e

Página 98 de 113
Se selecciona el DNI y el nombre, que es lo que se quiere mostrar, de la tabla Alumno.

SELECT a.DNI, a.nombre FROM alumno AS a

Seguidamente, se utiliza EXISTS, operador que comprueba la existencia de cualquier registro


en una subconsulta. En este caso se selecciona el DNI, pero se podrían 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. Si existen registros es que está
matriculado en alguna asignatura; da igual en cuál; solo es preciso saber que está matriculado
en alguna.

WHERE EXISTS (SELECT e.DNI FROM estudia AS e WHERE e.DNI = a.DNI);

Código completo:

SELECT a.DNI, a.nombre FROM alumno AS a


WHERE EXISTS (SELECT e.DNI FROM estudia AS e WHERE e.DNI = a.DNI);

Devuelve el DNI y nombre de los alumnos NO matriculados en alguna asignatura:

Se ha de utilizar el operador NOT EXISTS.

o Alias para la tabla alumno → a


o Alias para la tabla estudia → e

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:

SELECT a.DNI, a.nombre FROM alumno AS a

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:

WHERE NOT EXISTS (SELECT * FROM estudia AS e WHERE e.DNI = A.DNI);

Código completo:

SELECT a.DNI, a.nombre FROM alumno AS a


WHERE NOT EXISTS (SELECT * FROM estudia AS e WHERE e.DNI = a.DNI);

Ejemplo: Devuelve las asignaturas que no tienen alumnos:

o Alias para la tabla asignatura → as


o Alias para la tabla estudia (subconsulta) → e

En primer lugar, se seleccionan todos los atributos de la tabla Asignatura:

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.

SELECT * FROM asignatura AS as


WHERE NOT EXISTS (SELECT * FROM estudia AS e WHERE e.id_asignatura =
as.id_asignatura);

Los ejemplos siguientes se basan en la siguiente base de datos:

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.

Página 100 de 113


Consulta

Subconsulta

Subconsulta

o Alias para la tabla Empleado → e


o Alias para la tabla Proyecto (subconsulta 1) → p
o Alias para la tabla Proyecto_Empleado (subconsulta 2) → pe

Primero se selecciona el DNI y el sueldo del empleado:

SELECT e.DNI, sueldo FROM Empleado AS e,

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:

SELECT e.DNI, sueldo FROM Empleado AS e,


WHERE
NOT EXISTS (SELECT * FROM Proyecto AS p
WHERE
NOT EXISTS (SELECT * FROM Proyecto_Empleado AS pe
WHERE e.DNI = pe.DNI AND pe.ID_proyecto = p.ID_proyecto));

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.

Página 101 de 113


Ejemplo: Selecciona el DNI y sueldo de los empleados que trabajan en todos los proyectos.

Lo anterior se puede hacer de otra forma; y es con una subconsulta en el HAVING.

o Alias para la tabla Empleado → e


o Alias para la tabla Proyecto_Empleado → pe
o Alias para la tabla Proyecto (subconsulta) → p

Primero se selecciona el DNI y el sueldo de la tabla Empleado; y relacionamos la tabla Empleado


con la tabla Proyecto_Empleado para saber de cada empleado en qué proyectos trabaja:

SELECT e.DNI, sueldo FROM Empleado AS e, Proyecto_Empleado AS pe

Donde —WHERE— el DNI de la tabla Empleado coincida —=— con el DNI de la tabla
Proyecto_Empleado:

WHERE
e.DNI = pe.DNI

Agrupamos por DNI:

GROUP BY
e.DNI

Y en la condición de HAVING contamos en cuántos proyectos está trabajando esa persona —


COUNT(pe.ID_proyecto)— y lo igualamos —=— con el total de proyectos que tenemos
—(SELECT COUNT(p.ID_proyecto) FROM Proyecto AS p);—:

HAVING
COUNT(pe.ID_proyecto) = (SELECT COUNT(p.ID_proyecto) FROM Proyecto AS
p);

Si el COUNT() de proyectos de una persona concreta es igual al COUNT() de proyectos del


total de proyectos que tenemos, es que dicha persona trabaja en todos los proyectos.

Página 102 de 113


ICA0002-S04-C02

ICA0002-S4-C2-V1 Introducción a los JOIN


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102440)

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.

JOIN: ¿Qué es?

Técnicamente, el JOIN es una combinación de FROM + WHERE.

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.

JOIN: ¿Qué tipos hay?

Página 103 de 113


Los JOIN más conocidos son:

• INNER JOIN

• OUTER JOIN

Dentro de estos hay dos casuísticas especiales:

• Respecto a INNER JOIN → NATURAL JOIN

• Respecto a OUTER JOIN → NATURAL OUTER JOIN

Además, dentro del OUTER JOIN hay distintas tipologías: LEFT, RIGHT, FULL. Más adelante
las veremos.

También hay otros tipos de JOIN, como:

• CROSS JOIN

• STRAIGHT_JOIN

Y según el SGBD, aún es posible encontrar algún otro tipo de 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.

ICA0002-S4-C2-V2 INNER JOIN


(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102441)

INNER JOIN selecciona los registros que tienen valores coincidentes en ambas tablas.

Los ejemplos se basan en la siguiente base de datos:

Página 104 de 113


Ejemplo: Devuelve el DNI, nota e id de asignatura de los alumnos.

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…

SELECT a.DNI, e.nota, e.id_asignatura FROM alumno AS a, estudia AS e


WHERE a.DNI = e.DNI;

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

SELECT a.DNI, e.nota, e.id_asignatura FROM


(alumno AS a JOIN estudia AS e ON a.DNI = e.DNI);

Lo hecho con JOIN se puede hacer exactamente igual con INNER JOIN, puesto que JOIN e
INNER JOIN son sinónimos:

SELECT a.DNI, e.nota, e.id_asignatura FROM


(alumno AS a INNER JOIN estudia AS e ON a.DNI = e.DNI);

Página 105 de 113


Ejemplo: Devuelve el DNI, nota y nombre de asignatura de los alumnos de asignaturas
suspendidas.

o Alias para la tabla alumno → a


o Alias para la tabla estudia → e
o Alias para la tabla asignatura → as

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.

SELECT a.DNI, e.nota, as.nombre FROM alumno AS a, estudia AS e,


asignatura AS as

Luego, se relaciona los DNI de la tabla Alumno con los DNI de la tabla Estudia.

WHERE a.DNI = e.DNI

y (AND) las id_asignatura de la tabla Estudia con las id_asignatura de la tabla Asignatura.

AND e.id_asignatura = as.id_asignatura

Adicionalmente, como se quiere indicar la gente que ha suspendido, se indica también en la


condición de WHERE que la nota es menor a 5.

AND nota < 5;

Código completo:

SELECT a.DNI, e.nota, as.nombre FROM alumno AS a, estudia AS e,


asignatura AS as
WHERE a.DNI = e.DNI
AND e.id_asignatura = as.id_asignatura
AND nota < 5;

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.

Página 106 de 113


Código completo con JOIN:

SELECT a.DNI, e.nota, as.nombre FROM


(alumno AS a JOIN estudia AS e JOIN asignatura AS as
ON a.DNI = e.DNI AND e.id_asignatura = as.id_asignatura) WHERE nota <
5;

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.

Se puede escribir de dos maneras, que se verán mediante el siguiente ejemplo:

Ejemplo: Devuelve el DNI, nota e id de asignatura de los alumnos de asignaturas suspendidas.

Hay que juntar la tabla de Alumno y la tabla de Estudia para poder mostrar y filtrar la información
deseada.

En el primer caso, lo que se hace es utilizar el NATURAL JOIN directamente, y él mismo se


encargará de ver cómo puede relacionar la tabla de Alumno con la tabla de Asignatura.

o Alias para la tabla alumno → a


o Alias para la tabla estudia → e

SELECT a.DNI, e.nota, e.id_asignatura FROM


(alumno AS a NATURAL JOIN estudia AS e) WHERE nota < 5;

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.

SELECT a.DNI, e.nota, e.id_asignatura FROM


(alumno AS a NATURAL JOIN estudia AS e USING(DNI)) WHERE nota < 5;

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.

Página 107 de 113


ICA0002-S4-C2-V3 OUTER JOIN
(https://lasallefponline.sallenet.org/mod/videofile/view.php?id=102442)

Los ejemplos se basan en la siguiente base de datos:

El OUTER JOIN siempre va relacionado con una categoría de él mismo: LEFT, RIGHT o FULL.

LEFT OUTER JOIN

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.

Página 108 de 113


Ejemplo: Devuelve el DNI y su media de nota de todos los alumnos incluyendo los que no
tienen ninguna asignatura.

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:

SELECT a.DNI, AVG(e.nota) FROM


(alumno AS a LEFT OUTER JOIN estudia AS e ON a.DNI = e.DNI)
GROUP BY a.DNI;

LEFT OUTER JOIN es exactamente lo mismo que LEFT JOIN. Por tanto, el código superior
se podría escribir también así:

SELECT a.DNI, AVG(e.nota) FROM


(alumno AS a LEFT JOIN estudia AS e ON a.DNI = e.DNI)
GROUP BY a.DNI;

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.

Página 109 de 113


RIGHT OUTER JOIN

Es exactamente lo mismo que el LEFT OUTER JOIN, pero de forma inversa.

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:

SELECT AVG(e.nota), as.nombre FROM


(estudia AS e RIGHT OUTER JOIN asignatura AS as ON e.id_asignatura =
as.id_asignatura)
GROUP BY as.id_asignatura;

RIGHT OUTER JOIN es exactamente lo mismo que RIGHT JOIN. Por tanto, el código
superior se podría escribir también así:

SELECT AVG(e.nota), as.nombre FROM


(estudia AS e RIGHT JOIN asignatura AS as ON e.id_asignatura =
as.id_asignatura)
GROUP BY a.id_asignatura;

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.

Página 110 de 113


FULL OUTER JOIN

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:

(SELECT a.DNI, as.nombre FROM


(alumno AS a LEFT JOIN estudia AS e LEFT JOIN asignatura AS as
ON a.DNI = e.DNI AND e.id_asignatura = as.id_asignatura))
UNION
(SELECT a.DNI, as.nombre FROM
(alumno AS a RIGHT JOIN estudia AS e RIGHT JOIN asignatura AS as
ON a.DNI = e.DNI AND e.id_asignatura = as.id_asignatura));

Captura de pantalla del código:

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.

Página 111 de 113


NATURAL OUTER JOIN

NATURAL OUTER JOIN permite obviar/simplificar la manera de decir al sistema cómo se


relacionan las tablas. Será el propio NATURAL OUTER JOIN quien se encargará de buscar
qué elementos son los que relacionan las dos tablas.

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.

En el siguiente ejemplo, lo que se hace es seleccionar el DNI y la media de la nota utilizando un


NATURAL LEFT JOIN. Como es un NATURAL JOIN, del tipo OUTER —por eso tiene la
opción de LEFT—, lo hacemos directamente sin indicar qué atributos son los que relacionan la
tabla de Alumno con la tabla de Estudia.

Código completo:

SELECT a.DNI, AVG(e.nota) FROM


(alumno AS a NATURAL LEFT JOIN estudia AS)
GROUP BY a.DNI;

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:

SELECT a.DNI, AVG(e.nota) FROM


(alumno AS a NATURAL LEFT JOIN estudia AS USING(dni))
GROUP BY a.DNI;

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.

Página 112 de 113


Código completo con NATURAL RIGHT JOIN:

SELECT AVG(e.nota), as.nombre FROM


(estudia AS e NATURAL RIGHT JOIN asignatura AS)
GROUP BY a.id_asignatura;

Código completo con NATURAL RIGHT JOIN y el comando USING:

SELECT AVG(e.nota), as.nombre FROM


(estudia AS e NATURAL RIGHT JOIN asignatura AS USING(id_asignatura))
GROUP BY a.id_asignatura;

Página 113 de 113

También podría gustarte