Definición y manipulación de datos

IMPORTANTE: para esta lección necesitas tu base de datos, donde tienes permisos para utilizar los comandos de definición de datos.

Por definición de datos entendemos la creación de las estructuras de almacenamiento: crear bases de datos, crear tablas, índices, procedimientos, etc. También eliminarlas y modificarlas.

Por manipulación de datos, todo lo que tiene ver con el contenido de esas estructuras: consultar, insertar filas, borrar filas, modificar datos...

Como resumen de lo que se va a desarrollar a partir de aquí, veremos:

Create table

La definición de tablas es el primer paso en la creación de una base de datos. El conjunto de descripciones de tablas conforma el esquema de base de datos y representa a un sistema de información concreto.

Supongamos que vamos a implementar un esquema de base de datos relacional de profesores, asignaturas (sólo es un listado de profesores y asignaturas, sin relaciones entre ellos). En primer lugar debemos decidir cuáles son los atributos de cada uno de ellos y sus tipos de datos:

PROFESORES

DNI: varchar(10),

nombre: varchar(40),

categoria: char(4),

ingreso: date

ASIGNATURAS

codigo: char(5),

descripcion: varchar(35),

creditos: decimal(3,1),

creditosp: decimal(3,1)

Para cumplir con las restricciones del modelo relacional, además, debemos elegir las claves primarias adecuadas : DNI para profesores y código para asignaturas. Obviamente, la forma que tienen estas tablas ha sido una decisión nuestra como diseñadores de esta base de datos concreta, en otra situación hubiéramos, probablemente, decidido definir otros atributos y otras tablas.

La orden CREATE TABLE nos permite crear cada una de las tablas necesarias para nuestra base de datos:

CREATE TABLE nombreTabla ( {listaColumnas} [,{restricciones}] )


La lista de columnas, en su forma más sencilla, es un conjunto de expresiones (tantas como columnas deseemos, y separadas por comas) del tipo:

columna tipoDatos[,columna tipoDatos[, ...]]


La totalidad de tipos de datos que maneja MySQL, siendo la mayoría comunes con ligeras diferencias a cualquier motor de base de datos, se puede encontrar en https://mariadb.com/kb/en/data-types/.


Restricciones

Las restricciones son reglas, que normalmente se establecen en el momento de crear una tabla, para garantizar la integridad de los datos.

Básicamente, las restricciones obligan a cumplirse ciertas reglas cuando una fila es insertada, borrada o modificada, de forma que la operación se llevará a efecto sólo si se cumplen las restricciones definidas en la tabla.

Podemos contemplar los siguientes tipos de restricciones de integridad de datos:


De las restricciones,solo vamos a utilizar, de momento, la clave primaria, que puede contener tantas columnas como se necesiten:

PRIMARY KEY (columna[,columna[, ...]])

Ejecuta las siguientes órdenes para crear las tablas PROFESORES y ASIGNATURAS

create table profesores (

DNI varchar(10),

nombre varchar(40),

categoria char(4),

ingreso date,

primary key (DNI));


create table asignaturas (

codigo char(5),

descripcion varchar(35),

creditos decimal(3,1),

creditosp decimal(3,1),

primary key (codigo)); 


create table imparte (

dni varchar(10),

asignatura char(5),

primary key (dni,asignatura),

foreign key (dni) references profesores (DNI),

foreign key (asignatura) references asignaturas (codigo)); 

Motores de MariaDB/MySQL

Lo dicho hasta ahora constituye el estándar de SQL y es la sintaxis admitida en los SGBD de mayor penetración comercial. Eso no quita para que cada producto tenga sus pequeñas diferencias y peculiaridades.

MySQL ofrece varias opciones de almacenamiento y gestión de las tablas en aras de ofrecer alternativas que mejoren el rendimiento o la integridad de datos. En particular podemos elegir entre tablas MyISAM e InnoDB.

En MySQL, si queremos mantener integridad referencial entre nuestras tablas es imprescindible que especifiquemos que queremos usar el motor InnoDB. En una instalación estándar de MySQL, si no decimos nada, la creación de una tabla se hace por defecto en MyISAM y tiene un efecto importantísimo: si definimos claves ajenas, el sistema las ignora y no revisa la integridad referencial.

Eso nos obligaría a concretar el motor de almacenamiento tanto en las tablas con claves ajenas como en las referenciadas

create table profesores (...) engine=innodb;

create table asignaturas (...) engine=innodb;

create table imparte (...) engine=innodb

Motores de MariaDB

Al igual que se va a comentar a continuación, tenemos varias posibilidades de gestión del almacenamiento, algunas de ellas directamente relacionadas con la integridad referencial.

No obstante, y adelantándonos, si no especificamos nada MariaDB utiliza el motor innodb, y no hace falta añadir la cláusula engine=innodb a la creación de tablas, como sí exige MySQL. A partir de ahora, asumimos que trabajaremos con MariaBD y no incluiremos esa especificación.

Drop table

Si queremos borrar una tabla debemos ordenárselo al SGBD mediante la orden DROP TABLE:

DROP TABLE nombreTabla

Al utilizar esta orden también se eliminan los datos (las filas) que pudiera contener (en este caso, ninguna). Se puede borrar y crear la tabla tantas veces como queramos. 

No obstante, la definición de claves ajenas puede impedir el borrado de una tabla:

Borra la tabla asignaturas

drop table asignaturas;

/* Error de SQL (1451): Cannot delete or update a parent row: a foreign key constraint fails */

No podemos eliminar esta tabla porque IMPARTE.asignatura es clave ajena hacia ASIGNATURAS.codigo. Para poder eliminar ASIGNATURAS, debemos eliminar primero IMPARTE o, al menos, la definición de clave ajena.

drop table imparte;

drop table asignaturas;

Información del catálogo

Recordemos que ejecutar DESC nombreTabla o DESCRIBE nombreTabla, muestra información sobre las columnas que componen la tabla, el orden interno de las mismas en la tabla, y sus tipos de datos. La sentecia DESCRIBE es, en realidad, un atajo para acceder a las tablas del catálogo mediante una sentencia select

Antes de continuar, reconstruimos la tabla ASIGNATURAS:

create table asignaturas (

codigo char(5),

descripcion varchar(35),

creditos decimal(3,1),

creditosp decimal(3,1),

primary key (codigo));

En el momento de crear una restricción, además de especificar las reglas que se deben cumplir, podemos dar un nombre a la misma con constraint. Para establecer los nombres de las restricciones, se suele seguir el siguiente convenio: ser nombres descriptivos, que empiecen, por ejemplo, por

create table imparte (

dni varchar(10),

asignatura char(5),

constraint PK_imparte primary key (dni,asignatura),

constraint FK_imparte_profesores foreign key (dni) 

        references profesores (dni),

constraint FK_imparte_asignaturas foreign key (asignatura) 

        references asignaturas (codigo)) engine=innodb;

Obviamente, este convenio es eso, una recomendación, al sistema le da igual el nombre que elijamos.

Esto nos permite ejecutar órdenes como

-- Eliminar restricción de clave ajena

ALTER TABLE imparte DROP FOREIGN KEY FK_imparte_asignaturas;

No vamos a profundizar más en los nombres de las restricciones ni en la sintaxis para crearlos, pero sí que debemos saber que si no especificamos ningún nombre, el sistema le asignará un nombre único a cada restricción con un formato propio.

ALTER TABLE permite modificar una tabla sin eliminarla y volverla a crear. ALTER TABLE no se exigirá en los exámenes.

Insert

Para introducir datos nuevos en una base de datos vamos a utilizar la orden INSERT de SQL. Con la sintaxis que se muestra a continuación seremos capaces de introducir datos nuevos en cualquiera de las tablas que componen una determinada BD. En principio, veremos la expresión mínima de la orden, formada por dos cláusulas, INTO y VALUES.

INSERT INTO nombreTabla VALUES ( listaExpresiones )

Alta un nuevo profesor con los siguientes datos:

insert into profesores values ('55555555','PATRICIO MARTINEZ','TU','2000-1-1') 

Alta un nuevo profesor con los siguientes datos:

insert into profesores values ('66','ERNESTO PEREZ','ASO','1985-1-1'); 

El resultado que devuelve una orden INSERT, será siempre el número de filas insertadas, en el caso de que la ejecución haya sido correcta. Para los casos en que la ejecución de la sentencia viole alguna restricción de la BD y por tanto, su ejecución no sea correcta, el resultado indicará cuál es la restricción violada. El SGBD, cada vez que insertamos un nuevo dato en una tabla, se encarga de verificar las restricciones activas, en nuestro caso las claves primarias, que como sabemos, no admiten valores duplicados, ni valores nulos.

Alta un nuevo profesor con los siguientes datos:

insert into profesores values ('66','JUAN JUANITEZ','XXX','1905-1-1')

A veces no nos interesa o no podemos darle valor a todas y cada una de las columnas, o lo vamos a hacer en un orden distinto al que tienen las columnas en el create table que la definió. Especificar una lista de columnas antes de VALUES permite decirle al sistema qué columnas van a tener valor y cuál es. 

Da de alta a un profesor con DNI 88888888 y nombre ARMANDO SUÁREZ

insert into profesores (dni, nombre)

values ('88888888', 'ARMANDO SUAREZ');

El sistema intentará asignar a las columnas no indicadas el valor por defecto, si se ha definido, o  valor nulo. 

Es recomendable acostumbrarse a poner siempre las columnas a las que se va a dar valor, aunque vayan a ser todas las de la tabla. Las razones que lo aconsejan son:

Existe la posibilidad de hacer uso del valor NULL. Aunque se suele simplificar por "ausencia de valor", recuérdese que NULL significa realmente ignorancia —no sabemos si tiene valor ni, si lo tuviera, cuál es—. En cualquier caso, si la columna los admite, se pueden asignar en la orden de inserción.

insert into profesores (dni,nombre,categoría,ingreso)

values ('99999999','MARIA MIRO', NULL, NULL); 

El cambio de orden de las columnas se debe corresponder con la posición exacta del valor a asignar:.

insert into profesores (categoria, dni, nombre)

values (NULL, '77','ANA FERNANDEZ'); 

Inserción de más de una fila

Supongamos que en la BD Ejemplo existiera una tabla llamada OPTATIVAS que contuviera los códigos y los créditos de aquellas asignaturas de carácter optativo. 

Vamos a crear dicha tabla, eligiendo como clave primaria el código de la asignatura y poniendo además otra restricción, que todas las filas tengan un valor no nulo en la columna créditos 

create table optativas (

asignatura char (5), 

creditos decimal(3,1) not null,

primary key (asignatura)); 

Existe la posibilidad de insertar el resultado de una consulta en lugar de indicar la lista concreta de valores a insertar. Esto nos permite insertar varias filas en una tabla con una sola operación, en concreto, tantas filas como tuplas devuelva la orden SELECT.

INSERT INTO nombreTabla [ ( listaColumnas ) ] consulta 


Supongamos que serán optativas todas las asignaturas que tengan menos de 9 créditos. Se trata de introducir los códigos de dichas asignaturas en la tabla OPTATIVAS. En este caso, como ya tenemos las asignaturas en la tabla ASIGNATURAS, tenemos dos opciones. Una opción es, hacer la SELECT e ir haciendo las INSERT una a una, copiando los datos de las filas obtenidas. 

Otra opción es insertar en una sola operación el resultado de la SELECT en la tabla OPTATIVAS. 

insert into optativas (asignatura, creditos)

  select codigo, creditos 

  from asignaturas 

  where creditos < 9;

El resultado de la orden SELECT deberá ser coherente en cantidad de columnas y tipos de datos. Las siguientes órdenes provocarán errores de compilación: 

insert into optativas (asignatura) select codigo, creditos from asignaturas where creditos < 9;


insert into optativas (asignatura,creditos) select codigo from asignaturas where creditos < 9;


insert into optativas (asignatura,creditos) select dni,ingreso from profesores;

Este caso ya es diferente, hay que asegurarse de que el resto de columnas permiten la inserción. Con este tipo de órdenes, el motor de la base de datos asignará valores nulos al resto de columnas. Una situación típica es que alguna de las columnas omitidas no admita nulos e imposibilite la inserción.  

Revisa la definición de la tabla OPTATIVAS, y encontrarás la restricción NOT NULL sobre la columna creditos. El resultado será un mensaje de error, la restricción impide que se realice la inserción de filas para asegurar la integridad de los datos y, precisamente, evitando que se pongan valores nulos en esa columna.

insert into optativas (asignatura

select codigo from asignaturas 

where creditos < 9 

Delete

Antes de comenzar, limpiemos la base de datos

drop table if exists optativas;

drop table if exists imparte;

drop table if exists profesores;

drop table if exists asignaturas;


create table profesores (

DNI varchar(10),

nombre varchar(40),

categoria char(4),

ingreso date,

primary key (DNI));


create table asignaturas (

codigo char(5),

descripcion varchar(35),

creditos decimal(3,1),

creditosp decimal(3,1),

primary key (codigo));


create table imparte (

dni varchar(10),

asignatura char(5),

primary key (dni,asignatura),

foreign key (dni) references profesores (dni),

foreign key (asignatura) references asignaturas (codigo));


insert into asignaturas (codigo, descripcion, creditos, creditosp) values ('HI', 'HISTORIA DE LA INFORMATICA', 4.5, NULL), ('FBD', 'FUNDAMENTOS DE LAS BASES DE DATOS', 6.0, 1.5), ('DGBD', 'DISEÑO Y GESTION DE BASES DE DATOS', 6.0, 3.0), ('PC', 'PROGRAMACION CONCURRENTE', 6.0, 1.5), ('FP', 'FUNDAMENTOS DE LA PROGRAMACION', 9.0, 4.5);


insert into profesores (dni, nombre, categoria, ingreso) values ('21111222','EVA GOMEZ','TEU','1993-10-01'), ('21222333','MANUEL PALOMAR','TEU','1989-06-16'), ('21333444','RAFAEL ROMERO','ASO6','1992-06-16');


insert into imparte (dni, asignatura) values ('21111222','FBD'), ('21111222','DGBD'), ('21333444','PC');

La sentencia DELETE nos permite borrar las filas contenidas en una tabla.

DELETE [FROM] nombreTabla [WHERE condición]

¿Qué contiene IMPARTE ahora mismo?

select * from imparte; 

Borrar todas las filas de la tabla IMPARTE

delete from imparte;

Vuelve a comprobar

select * from imparte;

Borra todas las asignaturas de menos de 5 créditos

delete from asignaturas where creditos < 5;

Para borrar filas de varias tablas habrá que ejecutar tantas sentencias DELETE como tablas tengamos como objetivo.

(Nota: en MariaDB/MySQL se puede borrar sobre varias tablas pero no se puede asegurar que otros SGBD lo permitan también)

Update

Antes de comenzar, reconstruyamos la base de datos:

delete from imparte;

delete from profesores;

delete from asignaturas;


insert into asignaturas (codigo, descripcion, creditos, creditosp) values ('HI', 'HISTORIA DE LA INFORMATICA', 4.5, NULL), ('FBD', 'FUNDAMENTOS DE LAS BASES DE DATOS', 6.0, 1.5), ('DGBD', 'DISEÑO Y GESTION DE BASES DE DATOS', 6.0, 3.0), ('PC', 'PROGRAMACION CONCURRENTE', 6.0, 1.5), ('FP', 'FUNDAMENTOS DE LA PROGRAMACION', 9.0, 4.5);



insert into profesores (dni, nombre, categoria, ingreso) values ('21111222','EVA GOMEZ','TEU','1993-10-01'), ('21222333','MANUEL PALOMAR','TEU','1989-06-16'), ('21333444','RAFAEL ROMERO','ASO6','1992-06-16');


insert into imparte (dni, asignatura) values ('21111222','FBD'), ('21111222','DGBD'), ('21333444','PC');


La sentencia UPDATE nos permite modificar la información contenida en una tabla.

UPDATE nombreTabla [aliasTabla]

SET { {columna=expresion | columna=subconsulta} | listaColumnas=subconsulta}

[WHERE condición] 

No se pueden modificar varias tablas a la vez en una misma sentencia. Para modificar los valores de varias tablas habrá que ejecutar tantas sentencias UPDATE como tablas queramos modificar.

NOTA: no es del todo cierto.

Al igual que con delete, MariaBD/MySQL sí proporciona sintaxis específica para poder hacerlo, pero no podemos asegurar que otros SGBD también lo hagan o de la misma forma. 

Comprobemos el contenido actual de ASIGNATURAS:

select codigo,creditos from asignaturas; 

Modifiquemos los valores de la columna creditos:

update asignaturas set creditos = 0;

Y volvamos a comprobar:

select codigo,creditos from asignaturas;

Cuando se desea modificar más de una columna se indicará la lista de columnas y valores separadas por comas: 

Modifica los créditos de las asignaturas a 4, y los créditos prácticos a 2.

update asignaturas set creditos=4, creditosp=2;

En el caso de que se indique alguna condición, se modificarán sólo aquellas filas de la tabla que cumplan la condición o condiciones impuestas: 

Modifique la fecha de ingreso a 1 de enero de 2003 sólo a aquellos profesores cuya categoría sea TEU.

update profesores

set ingreso='01/01/2003'

where categoria = 'TEU';

Existe la posibilidad de modificar la información contenida en una tabla asignando como nuevo valor o valores, el resultado de una consulta.

El resultado de la consulta puede asignarse a una única columna o a una lista de columnas. En el primer caso, la sentencia SELECT sólo devolverá un valor (una fila y una columna) el cual debe coincidir en tipo de dato y longitud con el tipo de dato y longitud de la columna a la cual asignamos el valor. 

Es importante que nos aseguremos de que la subconsulta devuelve un único valor y que éste sea consistente con el tipo de dato esperado. 

update imparte  

set asignatura='BDA',

    dni = (select dni from profesores)

where asignatura like '%BD%';


ERROR:

la subconsulta de una sola fila devuelve más de una fila 

MariaDB/MySQL y delete-update

Es importante comprender que cada producto se acerca y se aleja del estándar de SQL en función de sus objetivos y de su estado de desarrollo. Sin ir más lejos, en MySQL es posible realizar borrados y modificaciones de filas de varias tablas en una única orden, cosa que otros SGBD (Oracle por ejemplo) no permiten.

Por otro lado, la siguiente orden funciona en otros SGBD pero MySQL no permite modificar una tabla a partir de una subconsulta de la misma tabla; si es necesario hay que crear una tabla temporal donde almacenar primero el valor y utilizarlo después en el update. Si se accede a la base de datos a través de un lenguaje de programación, Php por ejemplo, ya sería más normal almacenar el valor en una variable y hacer la modificación en base al mismo.

Supongamos que el contenido de la tabla PROFESORES es el que se muestra aquí.

Si quisiéramos ejecutar

Modica la fecha de ingreso de los profesores con categoría TEU para que coincida con la del profesor con DNI 21333444 

update profesores

set ingreso = (select ingreso from profesores where dni='21333444')

where categoria = 'TEU'; 

De esta orden se debería obtener: 

Sin embargo, MySQL devuelve un error con el mensaje, más o menos, "no se puede hacer un update de la misma tabla que se está consultando". Esto también ocurre con delete. La solución consiste en "engañar" a MariaDB/MySQL con una consulta temporal:

update profesores

set ingreso = (select ingreso 

               from (select ingreso 

                     from profesores 

                     where dni='21333444') ttemp

              )

where categoria = 'TEU';

En realidad no es que estemos "engañando" a MariaDB/MySQL; como se puede ver en el tema de "Tablas temporales", lo que estamos haciendo es generar una tabla temporal (ttemp) donde se copian los datos de PROFESORES que nos interesan.

MariaDB, a partir de la versión  10.3.2 no tiene esta limitación.