Creación de la base de datos[]
Aunque la creación de la base de datos de ejemplo se describió en el capítulo anterior, la incluimos la principio de éste como referencia:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca; USE videoteca; DROP TABLE IF EXISTS director; CREATE TABLE director ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) TYPE=InnoDB; DROP TABLE IF EXISTS genero; CREATE TABLE genero ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, nombre VARCHAR(2) NOT NULL, descripcion VARCHAR(32) NOT NULL, PRIMARY KEY(id) ) TYPE=InnoDB; DROP TABLE IF EXISTS actor; CREATE TABLE actor ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) TYPE=InnoDB; DROP TABLE IF EXISTS soporte; CREATE TABLE soporte ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, nombre VARCHAR(3) NOT NULL, descripcion VARCHAR(32) NOT NULL, PRIMARY KEY(id) ) TYPE=InnoDB; DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, titulo VARCHAR(64) NOT NULL, idsoporte INTEGER UNSIGNED NOT NULL, idgenero INTEGER UNSIGNED NOT NULL, PRIMARY KEY(id), INDEX p_FK1(idsoporte), INDEX p_FK2(idgenero), FOREIGN KEY(idsoporte) REFERENCES soporte(id), FOREIGN KEY(idgenero) REFERENCES genero(id) ) TYPE=InnoDB; DROP TABLE IF EXISTS actores_por_pelicula; CREATE TABLE actores_por_pelicula ( idpelicula INTEGER UNSIGNED NOT NULL, idactor INTEGER UNSIGNED NOT NULL, PRIMARY KEY(idpelicula, idactor), INDEX app_FK1(idpelicula), INDEX app_FK2(idactor), FOREIGN KEY(idpelicula) REFERENCES pelicula(id), FOREIGN KEY(idactor) REFERENCES actor(id) ) TYPE=InnoDB; DROP TABLE IF EXISTS directores_por_pelicula; CREATE TABLE directores_por_pelicula ( idpelicula INTEGER UNSIGNED NOT NULL, iddirector INTEGER UNSIGNED NOT NULL, PRIMARY KEY(idpelicula, iddirector), INDEX dpp_FK1(idpelicula), INDEX dpp_FK2(iddirector), FOREIGN KEY(idpelicula) REFERENCES pelicula(id), FOREIGN KEY(iddirector) REFERENCES director(id) ) TYPE=InnoDB;
Las inserciones necesarias para poder trabajar con este modelo son las siguientes:
USE videoteca; -- Antes de realizar todas las inserciones, -- borraremos todos los registros de las -- tablas de la base de datos. DELETE FROM actores_por_pelicula; DELETE FROM directores_por_pelicula; DELETE FROM actor; DELETE FROM director; DELETE FROM pelicula; DELETE FROM soporte; DELETE FROM genero; -- Inserciones de soportes para las películas. INSERT INTO soporte(nombre,descripcion) VALUES('DVD','Digital Versatile Disc'); INSERT INTO soporte(nombre,descripcion) VALUES('VHS','Video Home System'); -- Inserciones de géneros INSERT INTO genero(nombre,descripcion) VALUES('CF','Ciencia Ficción'); INSERT INTO genero(nombre,descripcion) VALUES('A','Aventuras'); INSERT INTO genero(nombre,descripcion) VALUES('D','Drama'); -- Inserciones de actores INSERT INTO actor(nombre,apellidos,imdb) VALUES('Harrison','Ford','nm0000148'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Russell','Crowe','nm0000128'); -- Inserciones de directores INSERT INTO director(nombre,apellidos,imdb) VALUES('Ridley','Scott','nm0000631'); INSERT INTO director(nombre,apellidos,imdb) VALUES('Mike','Nichols','nm0001566'); -- Inserciones de películas INSERT INTO pelicula(titulo,idsoporte,idgenero) VALUES('Blade Runner',1,1); INSERT INTO pelicula(titulo,idsoporte,idgenero) VALUES('Gladiator',1,2); INSERT INTO pelicula(titulo,idsoporte,idgenero) VALUES('A propósito de Henry',2,3); -- Asociación de actores a cada película. INSERT INTO actores_por_pelicula( idpelicula,idactor ) VALUES(1,1); INSERT INTO actores_por_pelicula( idpelicula,idactor ) VALUES(2,2); INSERT INTO actores_por_pelicula( idpelicula,idactor ) VALUES(3,1); -- Asociación de directores por película. INSERT INTO directores_por_pelicula( idpelicula,iddirector ) VALUES(1,1); INSERT INTO directores_por_pelicula( idpelicula,iddirector ) VALUES(2,1); INSERT INTO directores_por_pelicula( idpelicula,iddirector ) VALUES(3,2);
Algunas inserciones más:
USE videoteca; -- Inserciones de soportes para las películas. INSERT INTO soporte(nombre,descripcion) VALUES('LD','Laser Disc'); -- Inserciones de géneros INSERT INTO genero(nombre,descripcion) VALUES('C','Comedia'); -- Inserciones de actores INSERT INTO actor(nombre,apellidos,imdb) VALUES('Lee','Marvin','nm0001511'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Clint','Eastwood','nm0000142'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Jean','Seberg','nm0781029'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Bruce','Dern','nm0001136'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Bruce','Boxleitner','nm0000310'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Rutger',' Hauer','nm0000442'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Sean','Young','nm0000707'); INSERT INTO actor(nombre,apellidos,imdb) VALUES('Matthew','McConaughey','nm0000190'); -- Inserciones de directores INSERT INTO director(nombre,apellidos,imdb) VALUES('Robert','Zemekis','nm0000709'); INSERT INTO director(nombre,apellidos,imdb) VALUES('Douglas','Trumbull','nm0874320'); -- Inserciones de películas INSERT INTO pelicula(titulo,idsoporte,idgenero) VALUES('Naves misteriosas',1,1);
El modelo para DBDesigner puede encontrarse en la sección de descargas.
Operadores aritméticos[]
En nuestras cuentas sobre papel, representamos las operaciones de suma, resta, multiplicación y división utilizando operadores los aritméticos +, -, * y /, respectiva-mente. Con SQL no es diferente. Podemos realizar sumas con una simple consulta de selección:
SELECT 2 + 2;
Si en la tabla de películas almacenásemos el año en el que se estrenaron, podríamos saber cuántos años hace que se estrenó una determinada película con sólo restar al año actual el año de estreno. La consulta podría ser ésta:
USE videoteca; SELECT 2004 - estreno FROM pelicula WHERE id = 12;
Siguiendo con el ejemplo anterior, la siguiente instrucción calcularía el tiempo pasado desde el estreno de todas las películas de la base de datos:
USE videoteca; SELECT 2004 - estreno FROM pelicula;
Vamos a crear una tabla para hacer pruebas con los operadores en la base de datos de pruebas. Para crear esa base de datos, si no existe en su servidor:
DROP DATABASE IF EXISTS pruebas; CREATE DATABASE pruebas;
Ahora, para crear la tabla:
USE pruebas; DROP TABLE IF EXISTS operadores; CREATE TABLE operadores( uno TINYINT UNSIGNED, otro TINYINT UNSIGNED );
Insertemos un registro:
USE pruebas; INSERT INTO operadores VALUES(3,7);
El resultado de sumar los valores almacenados en las dos columnas de esta tabla se consigue así:
USE pruebas; SELECT uno + otro FROM operadores;
Obviamente, el resultado es 10. Pero, ¿cuál será el resultado de esta misma consulta, cuando insertemos esta nueva pareja de valores?
USE pruebas; INSERT INTO operadores VALUES(300,500);
Nos hemos salido de rango. Se trata de algo similar a lo que pasaría si intentásemos multiplicar dos valores enteros muy grandes, cuyo resultado estuviese por encima del máximo permitido por esa operación. Por ejemplo, tomemos el mayor número entero que podemos almacenar en MySQL y multipliquémoslo por 2:
SELECT 18446744073709551615 * 2;
El resultado: ese número menos uno. La razón, de nuevo, que hemos intentado almacenar en una columna un valor mayor que el que cabe en ella. Fíjese en que el resultado cambia si en lugar de multiplicar por 2 (entero) lo hacemos por 2,0 (coma flotante):
SELECT 18446744073709551615 * 2.0;
Operadores de comparación[]
Estos operadores nos permiten comparar dos valores. MySQL nos proporciona operadores para comprobar si dos valores son iguales (=) o diferentes (<>), si uno es mayor (>) o menor (<) que otro, y las variantes mayor o igual (>=), menor o igual (<=). Fíjese en los quebraderos de cabeza que nos puede dar NULL. Tanto es así, que hasta tenemos un operador de igualdad "a prueba de NULL": es el <=>. Probemos el operador de igualdad comparando dos parejas de valores:
SELECT 7 = 7, NULL = NULL;
Y ahora, el operador propio de NULL:
SELECT 7 <=> 7, NULL <=> NULL;
Podemos utilizar estos operadores para localizar elementos dentro de una tabla:
USE videoteca; SELECT * FROM actor WHERE apellidos = 'Crow';
El operador LIKE permite realizar comparaciones con cadenas parciales, utilizando algunos caracteres especiales:
SELECT * FROM actor WHERE apellidos LIKE 'Crow%';
Si lo desea, puede utilizar el carácter del guión bajo para buscar concordancias con un solo carácter, por ejemplo:
SELECT * FROM actor WHERE apellidos LIKE 'Crow_';
Operadores lógicos[]
Están basados en las premisas de la lógica booleana, en la que las operaciones básicas son NOT, AND, OR y XOR. Y precisamente estos son los nombres de los operadores. Podemos probar su funcionamiento así:
SELECT 0 AND 0, 0 AND 1, 1 AND 0, 1 AND 1
Cambio de precedencia[]
Se entiende por precedencia el orden en el que MySQL efectúa las operaciones de una determinada consulta. Puede comprobar cómo cambia ese orden utilizando paréntesis ejecutando la siguiente consulta:
SELECT 2 + 2 * 5, (2 + 2) * 5;
Manipulación de bases de datos[]
Las sintaxis de la sentencia de creación de base de datos es muy sencilla:
CREATE DATABASE [IF NOT EXISTS] nombre;
Tan sencilla como la creación, el borrado de bases de datos sigue la sintaxis:
DROP DATABASE [IF EXISTS] nombre;
Listados de una tabla[]
Veamos, ¿qué actores están dados de alta en nuestra base de datos? Seguro que sabe cómo obtener ese listado:
USE videoteca; SELECT * FROM actor;
Podemos indicar qué campos queremos obtener, por ejemplo el identificador, el nombre y los apellidos:
SELECT id,nombre,apellidos FROM actor;
Aunque también podemos concatenar nombre y apellidos en un solo campo:
SELECT id, CONCAT(nombre,' ',apellidos) FROM actor;
Esta última consulta tiene un problema "estético": el encabezado de la columna que muestra la concatenación. Para asignar un nombre a esa columna hemos de indicarlo tras la definición de la columna en la instrucción de selección:
SELECT id, CONCAT(nombre,' ',apellidos) AS nombre FROM actor;
Un posible cambio en esta consulta sería obtenerla ordenada por apellido y luego por nombre:
SELECT id, CONCAT(nombre,' ',apellidos) AS nombre FROM actor ORDER BY apellidos, nombre;
Pero, ¿cómo ordenar el resultado usando un campo calculado (como la concatenación)? Así:
SELECT id, CONCAT(nombre,' ',apellidos) AS nombre FROM actor ORDER BY 2;
Otra consulta que le resultará muy útil es la que permite contar el número de elementos de elementos en una determinada tabla:
SELECT COUNT(*) FROM actor;
Podemos utilizar el renombramiento de columnas:
SELECT COUNT(*) actores FROM actor;
Listados de varias tablas[]
Para realizar consultas de selección sobre más de una tabla es preciso indicarle a MySQL de qué tablas se trata, y cómo están relacionadas esas tablas. De nada nos serviría hacer una consulta como esta:
SELECT * FROM pelicula,actores_por_pelicula,actor;
Para poder organizar la información de estas tres tablas hemos de utilizar de forma diferentes la parte del FROM de la consulta, indicando ahí cómo se relacionan las tablas:
SELECT titulo, CONCAT(nombre,' ',apellidos) AS interprete FROM pelicula p JOIN actores_por_pelicula app ON p.id=app.idpelicula JOIN actor a ON app.idactor=a.id;
Vamos a incluir en esta consulta el director de la película:
SELECT p.titulo, CONCAT(a.nombre,' ',a.apellidos) AS interprete, CONCAT(d.nombre,' ',d.apellidos) AS director FROM pelicula p JOIN actores_por_pelicula app ON p.id=app.idpelicula JOIN actor a ON app.idactor=a.id JOIN directores_por_pelicula dpp ON p.id=dpp.idpelicula JOIN director d ON dpp.iddirector=d.id;
La siguiente consulta nos devuelve dos columnas: el nombre del actor en una de ellas, el número de películas en las que ha participado en la otra:
SELECT CONCAT(a.apellidos,', ',a.nombre) actor, COUNT(app.idpelicula) peliculas FROM actor a JOIN actores_por_pelicula app ON a.id=app.idactor GROUP BY a.id ORDER BY a.apellidos, a.nombre;
Pero, ¿y si queremos que aparezcan también los actores sin película en este listado? Podemos utilizar esta otra consulta:
SELECT CONCAT(a.apellidos,', ',a.nombre) actor, COUNT(app.idpelicula) peliculas FROM actor a LEFT JOIN actores_por_pelicula app ON a.id=app.idactor GROUP BY a.id ORDER BY a.apellidos, a.nombre;
Algunos de estos actores están dados de alta porque participan en una de las películas, pero aún no se les ha asociado a ella. Es el caso de Rutger Hauer y Sean Young, presentes en Blade Runner. Vamos a insertar los registros necesarios para que esa asociación exista. Primero necesitamos saber el identificador de la película Blade Runner:
SELECT id FROM pelicula WHERE titulo='Blade Runner';
Su identificador debería ser el 1. Ahora, los identificadores de los dos intérpretes:
SELECT id FROM actor WHERE nombre='Rutger' AND apellidos='Hauer';
Esta consulta nos... ¿no? ¿No devuelve nada? Pruebe a buscar sólo por el nombre, pero obtenga todos los campos, no sólo el identificador. Quizá haya un espacio antes del nombre. Intentémoslo con esta consulta:
SELECT id FROM actor WHERE nombre='Rutger' AND apellidos=' Hauer';
Ahora sí, ¿verdad? El identificador de este actor es el 8. ¿Y el de Sean Young?
SELECT id FROM actor WHERE nombre='Sean' AND apellidos='Young';
En la siguiente sección veremos cómo se modifican los valores almacenados en una tabla.
Actualizaciones[]
Necesitamos hacer un cambio en un determinado registro de la tabla de actores. Recuerde que el apellido de Rutger Hauer tenía un espacio al comienzo, algo que nos causó problemas en la sección anterior. Esta modificación se puede realizar de la siguiente forma:
USE videoteca; UPDATE actor SET apellidos='Hauer' WHERE nombre='Rutger';
Podremos eliminar los espacios que no nos interesan de nombres y apellidos en las tablas de actores y directores utilizando la siguiente consulta:
USE videoteca; UPDATE actor a, director d SET a.nombre=TRIM(a.nombre), a.apellidos=TRIM(a.apellidos), d.nombre=TRIM(d.nombre), d.apellidos=TRIM(d.apellidos);
Inserciones[]
Vamos a insertar los valores necesarios en la tabla de actores por película para que Rutger Hauer y Sean Young aparezcan en el reparto de Blade Runner. Podemos insertar el primero así:
INSERT INTO actores_por_pelicula( idpelicula,idactor ) VALUES(1,8);
O podemos hacer esto otro:
INSERT INTO actores_por_pelicula VALUES(1,9);
La primera instrucción hace referencia a Rutger Hauer, la segunda a Sean Young. Veamos el efecto de estas inserciones, seleccionando la información de reparto de Blade Runner:
USE videoteca; SELECT titulo, CONCAT(nombre,' ',apellidos) AS interprete FROM pelicula p JOIN actores_por_pelicula app ON p.id=app.idpelicula JOIN actor a ON app.idactor=a.id WHERE p.titulo='Blade Runner';
También podríamos construir una consulta que cuente el número de actores que tiene cada película:
USE videoteca; SELECT p.titulo, COUNT(app.idactor) interpretes FROM pelicula p LEFT JOIN actores_por_pelicula app ON p.id=app.idpelicula GROUP BY p.id;
Gracias a esta consulta de selección hemos localizado una inconsistencia en la base de datos: una película sin actores. ¿Existirá algún actor de esa película en la tabla de actores? Naves misteriosas fue protagonizada por Bruce Dern, entre otros. Si lo busca en la base de datos verá que aparece con el identificador 6. Para añadirlo como actor necesitamos saber el identificador de la película, que es el 4. Una nueva inserción en la tabla de actores por película solucionará el problema:
INSERT INTO actores_por_pelicula(idpelicula,idactor) VALUES(4,6);
Borrados[]
Quizá necesitemos hacer algún borrado en nuestra base de datos. Comprobemos qué formatos de grabación están disponibles:
USE videoteca; SELECT * FROM soporte;
¿Tenemos películas en todos esos formatos? Podemos saberlo con la siguiente consulta:
USE videoteca; SELECT s.nombre, COUNT(p.id) peliculas FROM soporte s LEFT JOIN pelicula p ON s.id=p.idsoporte GROUP BY s.id;
No existe ninguna película en formato LaserDisc. Eliminemos ese formato de nuestra tabla de soportes de grabación:
DELETE FROM soporte WHERE id=3;
Enlaces interesantes[]
Puede encontrar más información sobre las consultas en la documentación de MySQL, en concreto aquí.