Está en la página 1de 65

MANUAL DE SQL

BASES DE DATOS

MySQL al 99%

** Este documento se irá actualizando y ampliando a lo largo del curso

Curso 2022-2023
INDICE

1. CREACIÓN DE BASES DE DATOS ............................................................................... 6

1.1. Creamos la base de datos “base01”........................................................... 6

1.2. Borramos la base de datos “base01”.......................................................... 6

2. CREACIÓN DE TABLAS ............................................................................................. 7

2.1. Creamos una tabla ..................................................................................... 7

2.2. Creamos tablas indicando restricciones y valores por defecto ................... 7

2.3. Creamos tablas indicando clave primaria ................................................... 8

2.4. Verificamos que una tabla no exista antes de crearla ................................ 8

3. BORRADO DE TABLAS.............................................................................................. 9

4. MODIFICACIÓN DE LA ESTRUCTURA DE UNA TABLA ............................................... 10

4.1. Renombrar tablas ..................................................................................... 10

4.2. Eliminar n campos existentes ................................................................... 10

4.3. Añadir campos ......................................................................................... 10

4.4. Renombrar campos .................................................................................. 11

4.5. Cambiar el tipo de campo y su obligatoriedad .......................................... 11

4.6. Añadir una clave primaria ......................................................................... 11

4.7. Añadir un índice ....................................................................................... 11

4.8. Borrar un índice........................................................................................ 11

4.9. Crear claves ajenas ................................................................................. 12

4.10. Borramos claves ajenas ......................................................................... 13

5. INSERCIÓN DE REGISTROS ..................................................................................... 15

5.1. Formas de insertar registros..................................................................... 15

5.2. Insertando información en campos tipo blob ............................................ 16

2
5.3. Campos autoincrementales ...................................................................... 18

6. BORRADO DE REGISTROS ...................................................................................... 19

7. ACTUALIZACIÓN DE REGISTROS ............................................................................. 21

8. TRANSACCIONES................................................................................................... 23

8.1. Modo autocommit en la sesión ................................................................. 23

8.2. start transaction o begin ........................................................................... 24

9. SELECT ................................................................................................................. 25

9.1. Consultar todos los datos de la tabla ........................................................ 26

9.2. Consultar determinados campos de una tabla ......................................... 26

9.3. Utilizar sinónimos para el nombre de los campos..................................... 27

9.4. Obtener valores distintos .......................................................................... 27

9.5. Utilizar operadores y funciones en el apartado SELECT .......................... 28

9.6. Utilizar operadores y funciones en el apartado WHERE........................... 29

9.7. Agrupación de registros, Having y Group by ............................................ 31

9.8. Ordenar resultados .................................................................................. 32

9.9. Obtener n registros desde una posición ................................................... 33

9.10. Subselect ............................................................................................... 33

9.11. Union ..................................................................................................... 34

10. JOIN ................................................................................................................... 35

10.1. Inner Join ............................................................................................... 36

10.2. Left Join ................................................................................................. 37

10.3. Right Join ............................................................................................... 38

10.4. Natural Join ............................................................................................ 38

10.5. Natural Left Join ..................................................................................... 39

10.6. Natural Right Join ................................................................................... 39

3
11. SENTENCIAS DCL ................................................................................................ 40

11.1. Grant ...................................................................................................... 40

11.2. Revoke ................................................................................................... 41

12. VISTAS................................................................................................................ 43

12.1. Creación de una vista ............................................................................. 43

12.2. Borrado de una vista .............................................................................. 44

12.3. Modificación de una vista ....................................................................... 45

13. TRIGGERS ........................................................................................................... 46

13.1. Creación de un trigger ............................................................................ 46

13.2. Borrado de un trigger ............................................................................. 49

13.3. Modificación de un trigger ...................................................................... 49

14. PROCEDIMIENTOS .............................................................................................. 50

14.1. Procedimiento 1 - obtener_ventas_por_vendedor() ................................ 50

14.2. Procedimiento 2 - comparar_ventas() ..................................................... 51

14.3. Procedimiento 3 - listar comunidades() .................................................. 52

14.4. Procedimiento 3 – listado de televisores con cálculo de totales ............. 55

14.5. Procedimiento 4 – Marca con televisor más caro ................................... 58

14.6. Eliminación de un procedimiento ............................................................ 59

15. FUNCIONES ........................................................................................................ 60

15.1. Función 1 – listado de televisores con cálculo de totales ....................... 60

15.2. Función 2 – listado de televisores indicando las pulgadas en carácter ... 60

16. ANEXOS.............................................................................................................. 62

16.1. Vistas del sistema .................................................................................. 62

16.2. JS........................................................................................................... 63

16.3. Redireccionamiento de consultas a fichero ............................................ 63

4
16.4. Ejecución de ficheros .sql ....................................................................... 64

16.5. Otros comandos de interés .................................................................... 64

5
1. Creación de bases de datos

1.1. Creamos la base de datos “base01”

create database base01;

1.2. Borramos la base de datos “base01”

drop database base01;

6
2. Creación de tablas

2.1. Creamos una tabla

create table empleados (


nif varchar(9),
nombre varchar(25),
apellidos varchar(45),
edad integer,
fecha_alta (date);

2.2. Creamos tablas indicando restricciones y valores por defecto

Creamos la tabla de empleados donde indicamos que los campos:


- nif es obligatorio y su longitud debe ser mayor que 6
- nombre y apellidos son obligatorios
- Por omisión al insertar un registro en la tabla en los campos:
- fecha_alta: Guarda la fecha actual
- fecha_ascenso: Guarda la fecha y hora actuales
- hora_entrada: Guarda la hora actual
- edad: No se admite edades inferiores a 18
- estado: No puede ser nulo

create table empleados (


nif varchar(9) not null,
nombre varchar(25) not null,
apellidos varchar(45) not null,
edad integer Check (edad > 18),
fecha_alta date default CURDATE(),
fecha_ascenso datetime default now(),
hora_entrada time DEFAULT CURTIME(),
estado varchar(2) Check (estado is not null AND LENGTH(nif) > 6));

Creamos la tabla productos indicando que:


- El código del producto es obligatorio y no puede haber 2 registros con el mismo código. Al
ser un entero con signo su rango de valores es: -2147483648-2147483647
- El nombre del producto es obligatorio
- El precio unitario es tinyint, rango valores posibles con signo: -128 a 127
- El precio_lote es smallint, rango valores posibles con signo: -32768 a 32767
- Incremento, es tinyint pero al ser unsigned, rango valores posibles 0-255
- El precio_unitario debe ser menor a 10 (en este caso el nombre de la Constraint tipo check
es “tipo_unitario_10”, si ponemos el Check a nivel de campo como en el ejemplo anterior, el
nombre de la constraint tipo check es el nombre del campo que tiene la check.

7
create table productos (
codigo integer not null unique,
nombre varchar(30) not null,
precio_unitario tinyint,
precio_lote smallint,
incremento tinyint unsigned,
CONSTRAINT tipo_unitario_10 check (precio_unitario < 10));

2.3. Creamos tablas indicando clave primaria

Indicamos que la clave primaria es nif_vendedor + fecha_venta


Create table ventas (nif_vendedor char,
fecha_venta date,
importe_total double,
primary key (nif_vendedor, fecha_venta));

Cuando una tabla tiene una clave primaria con varios campos que la componen, este es el
formato con el que debe crearse. Si la tabla tiene una clave primaria con un solo campo
podríamos indicar:

Create table ventas (nif_vendedor char primary key,


fecha_venta date,
importe_total double,
primary key (nif_vendedor, fecha_venta));

Pero no es equivalente a la sentencia anterior porque con este formato no podemos indicar que
el campo “fecha_venta” también forma parte de la clave primaria.

2.4. Verificamos que una tabla no exista antes de crearla

Si la table existe, no se crea y no se genera un error

Create table if not exists ventas (nif_vendedor char,


fecha_venta date,
importe_total double,
primary key (nif_vendedor, fecha_venta));

8
3. Borrado de tablas

Borramos la tabla “ventas”. Esta instrucción borra el contenido y la estructura de la tabla ventas
con lo que para poder utilizarla tendríamos que volver a crearla. Si la tabla no existe, la sentencia
genera un error.
drop table ventas;
Borramos la tabla controlando que exista previamente, si la tabla no existe, la sentencia no ge-
nera un error.
drop table if exists ventas;

9
4. Modificación de la estructura de una tabla

Para modificar la estructura de una tabla, no es necesario borrarla y volverla a crear perdiendo
los datos existentes en ella, podemos realizar un Alter de la tabla modificando diferentes
aspectos de la misma.

4.1. Renombrar tablas

Podemos renombrar una tabla de 2 formas, por ejemplo vamos a renombrar la tabla
“empleados” y la vamos a llamar “usuarios”

a) rename table empleados to usuarios;


b) alter table empleados rename usuarios

4.2. Eliminar n campos existentes

Borramos varios campos (no contemplamos posibilidad de integridad con otras tablas)
alter table empleados drop column edad, drop column fecha_alta;

4.3. Añadir campos

Dada la tabla “ventas”:

Añadimos el campo “num_unidades” después de fecha venta y “stock” después de im-


porte_total (en vez de after también podemos usar before).
alter table ventas add column num_unidades integer after fecha_venta,
add column stock integer after importe_total;

Añadimos un campo al principio de la tabla


alter table ventas add column nombre varchar(45) first;

10
4.4. Renombrar campos

Renombramos el campo “importe_total” de la tabla de ventas a “importe_final” (debemos


indicar el tipo, con lo que además por este procedimiento podemos cambiar el tipo.

alter table ventas change importe_total importe_final integer;

4.5. Cambiar el tipo de campo y su obligatoriedad

alter table ventas modify importe_final varchar(3) not null;

4.6. Añadir una clave primaria

En la tabla productos, indicamos que el campo “código” es clave primaria:

ALTER TABLE productos


ADD PRIMARY KEY (codigo);

4.7. Añadir un índice

En la tabla ventas añadimos un índice que ordena la tabla ascendentemente por el campo
stock:

alter table ventas add index Indice_Stock1 (stock ASC);

4.8. Borrar un índice

En la tabla ventas borramos el índice “Indice_Stock1 “ que ordena la tabla “ventas”


ascendentemente por el campo stock:
drop index Indice_Stock1 on ventas;

11
4.9. Crear claves ajenas

Dadas las siguientes tablas:


Provincias Comunidades

Creamos una clave ajena en provincias con respecto a la tabla de comunidades por el
cod_comunidad. No permitimos que se creen provincias en la tabla de provincias cuya
comunidad no exista en la tabla de comunidades, para ellos deberemos crear la clave ajena con
una serie de parámetros:
ALTER TABLE provincias
ADD CONSTRAINT Clave_Ajena1
FOREIGN KEY (cod_comunidad)
REFERENCES comunidades (cod_comunidad)
ON DELETE RESTRICT
ON UPDATE RESTRICT;

Si no queremos indicar el nombre de la clave ajena “Clave_Ajena1” y dejar que sea MyQSL quién
ponga uno por omisión, de esta sentencia eliminaríamos “CONSTRAINT Clave_Ajena1”

Si modificamos los parámetros de ON DELETE y ON UPDATE, podemos determinar diferentes


formas de actuar de la clave ajena
RESTRICT (si no indicamos el tipo de restricción por omisión es RESTRICT)
- En la tabla de provincias no podemos tener una provincia que tenga un código de
comunidad que no exista en la tabla de comunidades, aunque podemos dejar el código de
comunidad con valor nulo.
- En la tabla de comunidades, no podemos cambiar el código de comunidad de un registro si
en la tabla de provincias hay una provincia que tenga dicho código de comunidad. Tampoco
podemos dar de baja dicho registro en la tabla de comunidades.

CASCADE

- En la tabla de provincias no podemos tener una provincia que tenga un código de


comunidad que no exista en la tabla de comunidades, aunque podemos dejar el código de
comunidad con valor nulo.
- Si se borra una comunidad del maestro de comunidades, se borran todas las provincias con
dicho código de comunidad del maestro de provincias.
- Si se modifica el código de comunidad de una comunidad autónoma en el maestro de
comunidades (por ejemplo, el código “02” se cambia por “88”); en el maestro de provincias,
se modifica el código de comunidad de todas las provincias de “02” a “88”.

12
SET NULL

- En la tabla de provincias no podemos tener una provincia que tenga un código de


comunidad que no exista en la tabla de comunidades, aunque podemos dejar el código de
comunidad con valor nulo.
- Si se borra una comunidad del maestro de comunidades, en todas las provincias del
maestro de provincias que tengan dicho código de comunidad, el código de comunidad se
modifica a nulos.
- Si se modifica el código de comunidad de una comunidad autónoma en el maestro de
comunidades (por ejemplo, el código “02” se cambia por “88”); en el maestro de provincias,
se pone a nulos el código de comunidad de todas las provincias en las que éste sea “02”

NO ACTION

El funcionamiento es igual que RESTRICT


¿Podemos definir una clave ajena al mismo tiempo que creamos la tabla? Por supuesto que sí.
CREATE TABLE provincias (cod_provincia varchar(2),
nom_provincia varchar(45),
cod_comunidad varchar(2),
CONSTRAINT clave_ajena1
FOREIGN KEY (cod_comunidad)
REFERENCES comunidades (cod_comunidad));

Si no ponemos los parámetros on delete y on update, es igual que indicar RESTRICT, es decir, la
sentencia anterior es equivalente a:
CREATE TABLE provincias (cod_provincia varchar(2),
nom_provincia varchar(45),
cod_comunidad varchar(2),
CONSTRAINT clave_ajena1
FOREIGN KEY (cod_comunidad)
REFERENCES comunidades (cod_comunidad)
ON UPDATE RESTRICT
ON DELETE RESTRICT);

Cuando creamos una clave ajena en una tabla, automáticamente en dicha tabla, se crea un
índice con el mismo nombre que la clave ajena, para el campo/s que constituye/n dicha clave.

4.10. Borramos claves ajenas

Para borrar una clave ajena, lo haremos con un ALTER puesto que estamos modificando la tabla.

13
ALTER TABLE provincias
DROP CONSTRAINT clave_ajena1;

El borrado de una clave ajena, no borra automáticamente el índice que se creó con el mismo
nombre en el alta de la misma. Por lo que deberíamos borrar el índice también, teniendo en
cuenta que no podremos borrar el índice asociado a la clave ajena si no hemos borrado antes la
clave ajena.

ALTER TABLE provincias


DROP INDEX clave_ajena1;

14
5. Inserción de registros

5.1. Formas de insertar registros

Tenemos varias formas de insertar registros en una tabla. Dada la siguiente tabla:

a) Insertamos un registro sin indicar el nombre de los campos. El número de datos que se
inserte por registro debe coincidir con el número de campos de la tabla, contemplándose
también el tipo. Vamos a ver varios ejemplos
INSERT INTO clientes VALUES ('4567898Z','Juan','Martín García', 24, '2022/10/22',False);
INSERT INTO clientes VALUES ('23546788S','Pedro','García García', 17, '2022-10-21',true);
INSERT INTO clientes VALUES ('83467889H','Roberto','Gómez López', 13, '2022-10-20',8);
INSERT INTO clientes VALUES ('22267889J','Alvaro','López Solís', 13, '22-11-02',7);
INSERT INTO clientes VALUES ('55646788W','Pablo','Fernández Soler', 13, '22-4-3',7);
INSERT INTO clientes VALUES ('12646788R','Ana','Martínez Olmo', '33', '22-4-3',false);

Hemos insertado 5 registros en la tabla pero vemos que el formato de los datos no es el mismo,
la fecha la podemos poner en varios formatos:
AAAA-MM-DD
AAAA/MM/DD o con el año con 2 dígitos
AA/MM/DD o AA-MM-DD
AA/M/D o AA-M-D

Vemos que en un campo Boolean estamos añadiendo true, false, 8,7. Esto es debido a que en
MySQL cuando creamos un campo como tipo Boolean, el gestor lo crea como Tinyint(1), aunque
se indique (1) el gestor nos permitiría introducir hasta el número 127 (si ponemos un número
superior lo trunca).
Si ponemos True, el gestor lo convierte en 1, si ponemos False, lo convierte en 0. Si incorporamos
un entero, para el gestor si = 0 es false y para <> 0 es true.

Vemos en el último Insert que podemos introducir un dato como texto en un campo numérico
'33' siempre que sea un número. Esto lo admite MySQL, la inversa también se admite.

15
b) Insertamos varios registros con un solo Insert
INSERT INTO clientes VALUES ('4567898Z','Juan','Martín García', 24, '2022/10/22',False),
('23546788S',null, '', 17, '2022-10-21',true);

Vemos qué si el campo no está definido como not null, podemos insertar en dicho campo el
valor null (ojo no es lo mismo que insertar este valor '' (2 comillas simples seguidas – campo
apellidos del segundo insert)

c) Insertamos un registro o varios indicando el nombre de los campos


insert into clientes (dni, nombre, edad) values('11145678C','Alfonso',12), ('54987656N',
'Juan',11) ;
En este caso, los campos que no indiquemos no pueden estar definidos como not null, y cuando
ejecutemos el insert, el valor NULL es el que tomarán todos los campos que no hayamos
indicado.

5.2. Insertando información en campos tipo blob

La información que se guarda en este tipo de campos, se guarda en formato binario, permi-
tiéndonos insertar Texto, imágenes, videos, documentos.
Dada la siguiente tabla:

16
a) Podemos insertar números, texto, boolean en el campo tipo blob
INSERT INTO skins values(1, 'El nombre de la skin es caballero medieval');
INSERT INTO skins values(2, 23);
INSERT INTO skins values(3, False); (en este caso, en el campo blob el false lo graba como 0

b) Podemos insertar imágenes, videos, pdf, etc en el campo tipo blob


INSERT INTO skins values(4, LOAD_FILE('c:/desarrollo/imagen1.jpg'));
Hay que tener en cuenta, sobre todo cuando insertamos imágenes, que podemos sobrepa-
sar el límite de paquete que tiene el servidor configurado por omisión, en este caso MySQL
nos mostrará un mensaje del tipo:
Warning (code 1301): Result of load_file() was larger than max_allowed_packet (xxxxxxx) -
truncated
Lo que nos indica que se está truncando la imagen, por lo que el resultado de la operación
no nos resulta válido.
Para solucionarlo debemos modificar el fichero de configuración my.ini para aumentar el
tamaño de la variable max_allowed_packet.
Por ejemplo: Si la imagen pesa < 10 Mb, editamos el archivo de configuración My.ini (en el
caso de xampp lo podemos hacer a través del menú principal):

Estamos aumentando el valor máximo de paquete a 10M, una vez grabado el fichero My.ini
reiniciamos el servidor.
Nos podría seguir dando un error de truncado de imagen, pero ya no sería un problema del
máximo tamaño permitido, sino del tipo de campo blob, el cual deberemos modificar al tipo
longblob
Una vez realizados los cambios, el insert de la imagen no nos debe producir ningún warning.

17
5.3. Campos autoincrementales

Un campo autoincremental, es un campo numérico cuyos valores se van incrementando


automáticamente a medida que vamos insertando registros en una tabla.
Podemos crear una tabla, con un campo de este tipo:
CREATE TABLE productos (
cod_producto INT AUTO_INCREMENT,
nom_producto VARCHAR(45),
precio double,
PRIMARY KEY (cod_producto)
);

- El valor por omisión de comienzo de la numeración es 1.


- El campo autoincremental debe ser numérico, se admiten int, double y float.
- El campo autoincremental debe ser clave.
- Sólo puede existir un campo autoincremental.
- El valor del campo autoincremental una vez creada la tabla (en su creación no se admite que
se indique el valor inicial) puede ser modificado mediante:
ALTER TABLE productos AUTO_INCREMENT=100, si hacemos esto y el número que indicamos
es menor al del último registro, el índice seguirá siendo el del valor más alto.
- Podemos asignar mediante una sentencia update o insert un valor al campo autoincremental,
en este caso el registro quedaría con dicho valor, si ese valor es el más alto, el índice del
autoincremento tomaría ese valor, si no, el índice quedaría como estaba
- Si borro el registro con la clave más alta, el índice de autoincremento no varía, no se
reaprovechan huecos, lo podríamos hacer pero actualizando manualmente el campo en los
registros.

18
6. Borrado de Registros

Veremos como borrar registros de una tabla, ya sea indicando un filtro o sin indicarlo, no
confundir con el borrado físico de la tabla, sólo vamos a borrar el contenido o parte del mismo,
no la estructura, la tabla sigue existiendo.
a) Borramos el contenido de toda una tabla.
DELETE FROM clientes
b) Borramos los registros de una tabla que cumplan una determinada condición, aquí veremos
una cláusula que nos permite especificar filtros tanto en borrado, como actualización o
consulta. Se trata de la cláusula WHERE.
Recordamos la estructura de la tabla clientes:

1) Borra los clientes cuyo Nif sea ‘23458765W’


DELETE FROM clientes WHERE dni = '23458765W';

2) Borra los clientes cuya edad esté entre 13 y 20 años sin incluir los que tengan 13.
DELETE FROM clientes WHERE edad > 13 AND edad <= 20;
<= Menor o igual – los símbolos deben ponerse en este orden
>= Mayor o igual – los símbolos deben ponerse en este orden

3) Borra los clientes cuya edad esté entre 13 y 20, incluidos los que tienen 13 y 20 años.
DELETE FROM clientes WHERE edad BETWEEN 13 AND 20;

4) Borra los clientes que tienen 13 años y son VIP


DELETE FROM clientes WHERE edad = 33 AND vip = True;

5) Borra los clientes que tienen entre 13 y 20 años (incluidos los de 13 y 20) o no son VIP

19
DELETE FROM clientes WHERE edad BETWEEN 13 AND 20 OR vip != True;

6) Borra los clientes cuya edad sea 24 o 13 o 17


DELETE FROM clientes WHERE edad IN (24,13,17);

7) Borra los clientes cuya edad no sea ni 24, ni 13 ni 17


DELETE FROM clientes WHERE edad NOT IN (24,13,17);

Como ya comentamos, la cláusula WHERE se utiliza también en actualizaciones y consultas y los


parámetros usados en estos ejemplos son válidos también para dichos casos.
En los próximos apartados veremos más parámetros de la Cláusula WHERE que podríamos usar
también a la hora de borrar registros.

20
7. Actualización de registros

La actualización de registros se realiza mediante la instrucción UPDATE


Aquí, de la misma forma que en el borrado de registros, sino indicamos un filtro (cláusula
WHERE, la actualización se realiza sobre todos los registros de la tabla).
a) Actualizamos todos los registros de una tabla.
UPDATE clientes set edad = 25;
Actualizamos todos los registros de los clientes en la tabla e indicamos que todos tienen 25 años.
b) Actualizamos todos los registros de la taba indicando para todos los clientes, edad 26 años y
la fecha de alta “2022-12-11”
UPDATE clientes set edad = 26, fecha_alta = '2022-12-11';
c) Actualizamos los registros de una tabla que cumplen una determinada condición, para ello
usamos la cláusula WHERE.
Tabla de clientes

1) Actualizamos edad a 15, para los clientes cuyo nombre empiece por “A”
UPDATE clientes set edad = 15 WHERE nombre LIKE 'A%';

2) Actualizamos edad a 19, para los clientes cuya segunda y cuarta letra del nombre sean “O” y
“E”
UPDATE clientes set edad = 19 WHERE nombre LIKE '_O_E%';

3) Actualizamos edad a 39, para los clientes cuyo nombre no acabe en “TO”
UPDATE clientes set edad = 39 WHERE nombre NOT LIKE '%TO';

4) Actualizamos edad a 28, para los clientes cuya edad sea nula

21
UPDATE clientes set edad = 28 WHERE edad IS NULL;

5) Actualizamos edad a Nulos, para los clientes cuya edad no sea nula
UPDATE clientes set edad = NULL WHERE edad IS NOT NULL;

22
8. Transacciones

Una transacción es un conjunto de operaciones que deben realizarse todas de forma correcta
para mantener la integridad de la información en la base de datos, si una sola de dichas opera-
ciones falla, deberían deshacerse todas para dejar la situación de la base de datos en el estado
anterior.
Por omisión, una sesión de shell de MySQL está en modo autocommit. Pero podemos cambiarlo
desde la shell:

8.1. Modo autocommit en la sesión

Set autocommit = 0

En este caso todas las operaciones que hagamos en la sesión sobre la base de datos, no se
realizan en firme hasta que ejecutemos la instrucción commit, si nos salimos de la shell sin
ejecutar un commit o ejecutamos un rollback (deshacer cambios) los cambios no se realizarán.
Esto afecta sólo a las instrucciones DML, las instrucciones DCL y DDL no se pueden gestionar en
términos transaccionales, en cuanto las ejecutamos su acción queda reflejada en la base de
datos de forma permanente.
Ej:
Tabla: aulas

Insertamos registro en modo autocommit = 1


insert into aulas values ('03', 'aula 3');

Situación antes de insert Operación después de insert Situación final


rollback
commit
<desconectar>

Insertamos registro en modo autocommit = 0


insert into aulas values ('03', 'aula 3');
Situación antes de insert Operación después de insert Situación final

23
commit

rollback
<desconectar>

8.2. start transaction o begin

Independientemente de cómo hayamos definido el autocommit, podemos trabajar en modo


transaccional a partir de un momento determinado mediante el uso de la sentencia start
transacction o la sentencia begin
Así, el siguiente conjunto de instrucciones no modificaría el contenido de la base de datos.

Estos 2 bloques de instrucciones son equivalentes


set autocommit = 1 set autocommit = 1
start transaction; begin;
insert into aulas values ('03', 'Aula 3'); insert into aulas values ('03', 'Aula 3');

Situación antes de ejecución Operación después de la eje- Situación final


de cualquier bloque cución de cualquier bloque
commit

rollback
<desconectar>

24
9. SELECT

Formato general:
SELECT [ ALL | DISTINCT} <campos que queremos mostrar>
FROM <tablas que vamos a usar>
[WHERE <condición> [AND | OR <condición>]]
[GROUP BY <nombres de los campos por los que agrupar>}
[HAVING <criterios por los que agrupar>]
[ORDER BY <nombre de los campos por los que ordenar> | <nº del campo>
[ASC|DESC]];

Esta instrucción permite obtener información de una o varias tablas de la base de datos,
estableciendo filtros, agrupando registros y realizando cálculos parciales y totales.
Dada la siguiente tabla y contenidos vamos a realizar algunas consultas:

Tabla: coches

Veremos ahora el contenido de la tabla para lanzar diferentes consultas, pero antes, ¿por qué
el campo cod_almacen lo definimos como char(5) y el resto de campos, tipo texto los definimos
como varchar? ¿qué diferencia hay?.
Char(5)
- Cuando insertamos un registro, Mysql reserva para el campo 5 bytes aunque introduzcamos
menos caracteres, ese espacio se desaprovecha.
- La grabación de datos en este tipo de campos es más rápida.
- El límite de longitud admitido en Mysql es 255.
- Si sabemos que la mayoría de los datos o todos tienen 5 caracteres, es conveniente utilizar
este tipo.

25
Varchar(5)
- Cuando insertamos un registro, Mysql no reserva un espacio de 5 bytes, sino la longitud de
la información introducida, más un añadido con el control de la longitud del campo; por
ejemplo, si añadimos el almacén “A12” reserva 3 bytes + 1 (en éste último se almacena la
longitud del contenido que es 3).
Si la longitud del campo es muy grande y la longitud de los datos introducidos lo es también,
puede ser necesario el uso de más bytes para almacenar la longitud de los datos.
- Son más lentos en actualización pero permiten ahorrar espacio.
- Su longitud es mucho mayor que en el caso de los Char > 16000 Bytes

Datos ejemplo de la tabla

La sentencia Select permite consultar determinados datos de una tabla, permitiendo realizar
operaciones con ellos:

9.1. Consultar todos los datos de la tabla

SELECT * FROM coches;

9.2. Consultar determinados campos de una tabla

SELECT marca, modelo, precio FROM coches;


SELECT ALL marca, modelo, precio FROM coches;
(Estas 2 instrucciones son equivalentes)

26
9.3. Utilizar sinónimos para el nombre de los campos

A veces los nombres de los campos de una tabla no nos resultan muy significativos, por lo que
podemos ponerles alias y así en la cabecera de las consultas ver dichos alias, por ejemplo, en la
consulta anterior queremos renombrar el campo precio como precio_unitario.
SELECT marca, modelo, precio as precio_unitario FROM coches;

Los sinónimos de los campos no se pueden utilizar en la cláusula “WHERE” ni “ORDER” pero sí
en la cláusula “HAVING”, estas cláusulas las veremos más adelante.

9.4. Obtener valores distintos

SELECT DISTINCT marca, modelo FROM coches;


Devuelve las distintas marcas/modelos existentes en la tabla.

27
9.5. Utilizar operadores y funciones en el apartado SELECT

SELECT precio * unidades FROM coches; (mostramos el campo precio * unidades)

SELECT precio + 1000 FROM coches; (mostramos el precio de los coches + 1000)
De igual forma podemos realizar divisiones y restas

SELECT CONCAT(marca, ' - ',modelo,' - ', color) as 'Datos Generales' FROM coches; (se concatena
el valor de los campos marca, modelo y color separándolos por guiones)

SELECT SUM(unidades) FROM coches; (se muestra la suma total del campo “unidades” en todos
los registros – Se muestra el total de coches)

SELECT AVG(precio) FROM coches; (muestra la media del precio existente en el campo “pre-
cio” de todos los registros).

SELECT TRUNCATE(AVG(precio),1) FROM coches; (muestra la media del precio existente en el


campo “precio” de todos los registros truncada a 1 decimal).

SELECT MIN(precio) FROM coches; (muestra el precio más bajo de la tabla)

28
SELECT MAX(precio) FROM coches; (muestra el precio más alto de la tabla)

SELECT COUNT(*) FROM coches; (muestra el número total de registros de la tabla

Si hacemos un count sobre un campo, por ejemplo:


SELECT COUNT(precio) from coches
Esta instrucción me devolvería el número de registros de la tabla donde el campo precio no sea
nulo.

9.6. Utilizar operadores y funciones en el apartado WHERE

WHERE nos permite restringir el ámbito de la consulta, es decir, nos permite establecer un filtro
que nos permite seleccionar sólo los registros que cumplan unas determinadas condiciones.
➢ OR
SELECT * FROM provincias WHERE cod_provincia = '01' OR cod_provincia= '02'; Muestra las
provincias de España cuyo código sea '01' o '02'

➢ AND
SELECT * FROM provincias WHERE cod_provincia = '01' AND cod_comunidad= '01'; Muestra
las provincias de España cuyo código de provincia sea '01' y el código de comunidad sea '01'.
En este caso la consulta no devuelve ningún registro porque Álava corresponde a la comunidad
'16'.

➢ IN

29
SELECT * FROM PROVINCIAS WHERE COD_PROVINCIA IN ('01', '02', '03'); Muestra las provincias
de España cuyo código sea '01' o '02' o '03'

➢ BETWEEN
SELECT * FROM provincias WHERE cod_provincia BETWEEN '03' AND '05'; Muestra las
provincias de España cuyo código esté dentro del intervalo '03'-'05' ambos extremos del
intervalo incluidos.

SELECT * FROM ventas WHERE fec_operacion BETWEEN '2022-01-01' AND '2022-01-05';


Muestra las ventas cuya fecha de operación esté entre el 01/01/2022 y el 05/01/2022

➢ LIKE
SELECT * FROM provincias WHERE nom_provincia LIKE '%lav%'; Muestra las provincias que
contienen la cadena “lav”. LIKE no es sensible a mayúsculas y minúsculas ni a los acentos.

SELECT * FROM provincias WHERE nom_provincia LIKE '_L%'; Muestra las provincias cuya
segunda letra de su nombre sea una L.

30
SELECT * FROM provincias WHERE nom_provincia LIKE '____'; Muestra las provincias cuyo nom-
bre tenga 5 de longitud (hay 5 '_' en el LIKE)

El operador LIKE se puede utilizar con múltiplos patrones, por ejemplo SELECT * FROM
provincias WHERE nom_provincia LIKE '[A-B]' devolvería todos los registros cuyo primer carácter
del campo nom_provincia estuviese entre A y B. Esto en MYSQL no es un estándar, en MYSQL
sería: SELECT * FROM provincias WHERE nom_provincia REGEXP '^[a-b]';

➢ NOT
Si se indica NOT delante de cualquier operador o palabra reservada LIKE, IN, Between, muestra
el resultado complementario.
Negar una igualdad se puede indicar como != o por NOT delante de la condición completa, por
ej: SELECT * FROM provincias WHERE NOT nom_provincia = 'Alava'; Muestra todas las
provincias menos Álava.

➢ IS
Podemos seleccionar los registros cuyo código de provincia sea nulo mediante:
SELECT * FROM provincias WHERE cod_provincia is null;
O seleccionar los que no sean nulos
SELECT * FROM provincias WHERE cod_provincia is not null

9.7. Agrupación de registros, Having y Group by

Podemos realizar agrupaciones de registros.

31
Mostramos el número de registros que hay por marca así como la suma de todas las unidades
existentes de cada marca.
SELECT marca, COUNT(*), SUM(unidades)
FROM coches
GROUP BY marca;

Mostramos el número de registros que hay por marca así como la suma de todas las unidades
existentes de cada marca, pero sólo si la suma de todas las unidades de la marca supera 20.

SELECT marca, COUNT(*), SUM(unidades)


FROM coches
GROUP BY marca HAVING SUM(unidades) > 20;

Mostramos las diferentes marcas y modelos (group by), el número de registros por marca/mo-
delo y la suma de las unidades existentes para cada marca/modelo sólo en el caso en que la
suma de dichas unidades sea > 5 o que la marca sea “Audi”
SELECT marca, modelo, COUNT(*), SUM(unidades)
FROM coches
GROUP BY marca, modelo HAVING SUM(unidades) > 5 OR marca = "Audi";

Mostramos el número de registros totales de aquellas marcas que no sean “Audi”.


SELECT marca, COUNT(*) FROM coches
GROUP BY marca HAVING marca != "Audi ";

El no igual se puede marcar como != o bien <>

9.8. Ordenar resultados

Muestra todos los datos de la tabla, ordenados por, marca de forma descendente y modelo de
forma ascendente (por omisión las ordenaciones son ascendentes).

32
Conviene tener creado un índice en la tabla con los campos por los que se efectúa la
ordenación.
SELECT * FROM coches ORDER BY marca DESC, modelo ASC;

9.9. Obtener n registros desde una posición

La siguiente instrucción obtiene los 3 registros siguientes a partir del registro 2 que devuelve la
consulta, LIMIT también se puede utilizar para borrar los registros de dicho intervalo.
SELECT * FROM coches ORDER BY marca DESC, modelo ASC LIMIT 2,3;

Esta instrucción muestra los registros 2,3 y 4 de la consulta (el primer registro es el 0).
LIMIT 0,3 devolvería los 3 primeros registros (0,1 y 2), si indicamos LIMIT 3 sin indicar el valor de
inicio del intervalo, MySQL asume que es LIMIT 0,3.

9.10. Subselect

La siguiente sentencia muestra las provincias cuyo nombre de comunidad autónoma empieza
por “a”, para ello se seleccionan todos los códigos de comunidades autónomas cuyo nombre
empieza por “a” a través de una subselect.
SELECT * FROM PROVINCIAS WHERE cod_comunidad IN (SELECT cod_comunidad FROM
Comunidades where nom_comunidad like 'a%' );

El uso de subselect tiene un muy bajo rendimiento y está prohibido en la mayoría de las
empresas.

33
9.11. Union

Este operador permite combinar resultados de dos o más consultas independientes, siendo
requisito que el número de campos a mostrar de cada una de las consultas sea el mismo.
Ejemplo:
SELECT marca FROM coches1 UNION SELECT marca from coches2
Muestra el resultado de ambas consultas como si fuese una, teniendo en cuenta que para
aquellos registros con todos sus valores duplicados, no será mostrado más que uno de ellos. Si
queremos que se muestren todos los registros incluido los duplicados, el formato de la sentencia
cambia:
SELECT marca FROM coches1 UNION ALL SELECT marca from coches2

34
10. JOIN

Normalmente nos encontraremos con la necesidad de cruzar varias tablas según determinados
criterios para obtener un resultado, para ello será necesario que realicemos JOIN entre tablas.
Las Join se pueden realizar de varias formas, utilizando la igualdad de campos en la cláusula
WHERE o mediante Inner join, left Join, Right Join
Vamos a trabajar con 3 tablas, cuya estructura es la siguiente:

Tabla Empleados (nif, nombre y apellidos del empleado, matrícula del coche que tiene
asignado y categoría profesional).

Tabla Coches (matricula, marca, modelo, color y código país de fábrica del coche).

Tabla Países (código de país y nombre del país).

Modelo:

35
10.1. Inner Join

La siguiente sentencia, muestra el nif, el nombre y los apellidos de los empleados existentes en
la tabla “empleados” y la marca y modelo del coche existente en la tabla “coches”. El nexo de
unión entre ambas tablas es la matrícula del coche. Los resultados se mostrarán ordenados por
el nombre y apellidos del empleado.
Utilizamos alias en los nombres de tablas para acortar la sentencia y en los nombres de los
campos para que se nos muestren dicho alias en las cabeceras, al ser más descriptivos que los
nombres de los campos.
La palabra clave INNER es opcional, se puede no poner y la sentencia es equivalente.
Inner Join, devuelve la intersección de ambas tablas (empleados y coches), si hubiese
matrículas de coches en la tabla de empleados que no existieses en la tabla de coches, dichos
empleados no aparecerían en el resultado de la consulta.
SELECT
T1.nif as 'nif del empleado',
T1.nombre as 'nombre del empleado',
T1.apellidos as 'apellidos del empleado',
T2.marca as 'marca del coche asignado',
T2.modelo as 'modelo del coche asignado'
FROM empleados T1
INNER JOIN coches T2
ON T1.matricula_ca = T2.matricula
ORDER BY t1.nombre, t1.apellidos;

Resultado:

Otra forma de efectuar esta Join es definiendo la relación de los campos en la cláusula WHERE.

SELECT
T1.nif as 'nif del empleado',
T1.nombre as 'nombre del empleado',
T1.apellidos as 'apellidos del empleado',
T2.marca as 'marca del coche asignado',
T2.modelo as 'modelo del coche asignado'
FROM empleados T1, coches T2
WHERE T1.matricula_ca = T2.matricula
ORDER BY t1.nombre, t1.apellidos;

36
A continuación, mostramos un ejemplo de INNER JOIN con las 3 tablas.
Además de los datos anteriores, mostramos el nombre del país donde se fabrica el coche que
tiene asignado el empleado.

select
T1.nif as 'nif del empleado',
T1.nombre as 'nombre del empleado',
T1.apellidos as 'apellidos del empleado',
T2.marca as 'marca del coche asignado',
T2.modelo as 'modelo del coche asignado',
T3.nombre_pais as 'país de fabricación'
FROM empleados T1
JOIN coches T2 on T1.matricula_ca = T2.matricula
JOIN paises T3 on T2.cod_pais_fabrica = T3.cod_pais;

Resultado:

10.2. Left Join

Devuelve los datos comunes entre 2 tablas (o más), en el caso de 2, devuelve los datos de ambas
donde coincidan las claves de los registros, más los registros de la primera tabla que no están en
la segunda.
También se puede indicar Left Outer Join, el funcionamiento es el mismo.
SELECT
T1.nif as 'nif del empleado',
T1.nombre as 'nombre del empleado,',
T1.apellidos as 'apellidos del empleado',
T1.matricula_ca as 'Matricula coche',
T2.marca as 'marca del coche asignado',
T2.modelo as 'modelo del coche asignado'
FROM empleados T1
LEFT JOIN coches T2
ON T1.matricula_ca = T2.matricula

37
ORDER BY t1.nombre, t1.apellidos;

Resultado:

10.3. Right Join

Devuelve los datos comunes entre 2 tablas (o más), en el caso de 2, devuelve los datos de ambas
donde coincidan las claves de los registros, más los registros de la segunda tabla que no están
en la primera.
También se puede indicar Right Outer Join, el funcionamiento es el mismo.
SELECT
T1.nif as 'nif del empleado',
T1.nombre as 'nombre del empleado',
T1.apellidos as 'apellidos del empleado',
T1.matricula_ca as 'Matricula coche',
T2.marca as 'marca del coche asignado',
T2.modelo as 'modelo del coche asignado'
FROM empleados T1
RIGHT JOIN coches T2
ON T1.matricula_ca = T2.matricula
ORDER BY t1.nombre, t1.apellidos;

Resultado:

10.4. Natural Join

Devuelve los datos comunes entre 2 tablas (o más), en el caso de 2, devuelve los datos de ambas
donde coincidan en valor los campos que tengan el mismo nombre en las tablas; por ello en el
natural join no es necesario indicar los campos a relacionar.

SELECT * FROM empleados NATURAL JOIN coches;

38
Entre las tablas coches y empleados, si no hay 2 campos con el mismo nombre, la instrucción
“natural join” nos devuelve el producto cartesiano de ambas tablas.
Si el campo “matrícula” del coche se llamase igual en ambas tablas (modificamos el campo
“matricula_ca” de la tabla empleados a “matricula” para que así sea), el resultado de la consulta
sería:

Esta instrucción es equivalente a:

SELECT * FROM empleados T1 INNER JOIN coches T2 ON T1.matricula = T2.matricula;

Siendo la única diferencia, que en este segundo caso si se indica Select *, se respeta el orden de
las columnas, no se sitúa en primer lugar la columna por la que se hace el Join.

10.5. Natural Left Join

Su funcionamiento es el equivalente a Left Join, excepto que no hay que indicar los campos
que se están cruzando, son los que coincidan en el nombre.
También se puede indicar Natural Left Outer Join, el funcionamiento es el mismo.

10.6. Natural Right Join

Su funcionamiento es el equivalente a Right Join, excepto que no hay que indicar los campos
que se están cruzando, son los que coincidan en el nombre.
También se puede indicar Natural Right Outer Join, el funcionamiento es el mismo.

39
11. Sentencias DCL

Permiten revocar y dar permisos a los usuarios para acceder a determinada operativa.

select
Insert
Delete
update

Las sentencias DCL son:


GRANT: Permite otorgar determinados privilegios a un usuario
REVOKE: Elimina determinados privilegios a un usuario

Crearemos usuarios con una sentencia DDL: CREATE USER:


CREATE USER usuario1@localhost IDENTIFIED BY 'pwdusuario1';
Con esta sentencia, creamos el usuario1 contra el servidor local (si es contra un servidor remoto
indicaríamos su IP en vez de localhost). Cuando creamos un usuario con este formato, no le
damos permiso a nada, no podría ni conectarse al servidor con connect.
DROP USER usuario1@localhost; Elimina el usuario

11.1. Grant

SHOW GRANTS FOR CURRENT_USER(); permite ver los permisos del usuario actual
SHOW GRANTS FOR usuario1@localhost; permite ver los permisos del usuario1
Algunas de estas sentencias no funcionan sobre XAMPP pero si sobre un MySQL Nativo.

1) Damos permisos al usuario1 para que pueda consultar registros a través de la vista
“view_provincias” de la base de datos “base01”

GRANT SELECT ON VIEW base01.view_provincias to usuario1@localhost;


2) Damos permisos al usuario1 para que pueda realizar todo tipo de operaciones en todas las
bases de datos.

GRANT ALL PRIVILEGES ON *.* TO usuario1@localhost;


3) Damos permisos al usuario1 para que pueda realizar todo tipo de operaciones en la base de
datos base01.

GRANT ALL PRIVILEGES ON base01.* TO usuario1@localhost;

40
4) Damos permisos al usuario1 para que pueda realizar cualquier operación sobre la tabla
“ventas” de la base de datos “base01”

GRANT ALL PRIVILEGES ON base01.ventas TO usuario1@localhost;

5) Damos permisos al usuario1 para que pueda realizar determinada operativa sobre la tabla
“ventas” de la base de datos “base01”

GRANT SELECT, INSERT, UPDATE, DELETE ON base01.ventas TO usuario1@localhost;


Podemos indicar uno o varios permisos a la vez (select, insert, update, delete)
6) Damos permisos al usuario1 para que pueda crear tablas en la base de datos “base01”

GRANT CREATE ON base01.* TO usuario1@localhost;


En Mysql con “create on” damos permisos para crear tablas, no indicamos expresamente que
podemos crear tablas, si en vez de * pusiéramos un nombre, solo podríamos crear una tabla
con ese nombre
7) Damos permisos al usuario1 para borrar una tabla concreta de la base de datos “base01”

GRANT DROP ON base01.empleados TO usuario1@localhost;


8) Damos permisos al usuario1 para modificar una tabla concreta de la base de datos “base01”,
por ejemplo podríamos crear un índice una vez dado el permiso

GRANT ALTER ON base01.empleados TO usuario1@localhost;


Esta instrucción nos permitiría ejecutar por ejemplo:

ALTER TABLE base01.empleados


ADD INDEX indice1 (nom_empleado ASC);
9) Traspasamos al usuario1 la posibilidad a su vez de dar permisos a otros usuarios que él
tiene sobre la base de datos “base01”

GRANT GRANT OPTION ON base01.* TO usuario1@localhost;


Si el usuario tiene permisos para crear tablas, en la base de datos “base01”, pues se le otorgó
mediante: GRANT CREATE ON base01.* TO usuario1@localhost; el usuario1 podría lanzar esa
misma instrucción para permitir crear tablas en la base de datos “base01” al usuario2.

11.2. Revoke

Algunas de estas sentencias no funcionan sobre XAMPP pero si sobre un MySQL Nativo.

1) Quitamos todos los permisos al usuario1

REVOKE ALL ON *.* from usuario1@localhost;

41
2) Quitamos todos los permisos para la base de datos “base01” al usuario1

REVOKE ALL ON base01.* from usuario1@localhost;


3) Quitamos todos los permisos para la base de datos “base01” tabla “ventas” al usuario1

REVOKE ALL ON base01.ventas from usuario1@localhost;

4) Quitamos algunos permisos para la base de datos “base01” tabla “ventas” al usuario1

REVOKE SELECT, INSERT, UPDATE, DELETE ON base01.ventas from usuario1@localhost;


Podemos indicar uno o varios permisos a la vez (select, insert, update, delete)
5) Quitamos permisos para creación de tablas en una base de datos

REVOKE CREATE ON base01.* FROM usuario1@localhost;


6) Quitamos permisos para borrar una tabla concreta de la base de datos “base01” al usuario1

REVOKE DROP ON base01.empleados FROM usuario1@localhost;


7) Quitamos permisos para modificar una tabla concreta de la base de datos “base01” al
usuario1

REVOKE ALTER ON base01.empleados FROM usuario1@localhost;

42
12. Vistas

Permite grabar en base de datos una consulta como si fuera una vista de tal forma que se pue-
das lanzar consultas directamente sobre la vista.
Limitaciones:
- No pueden existir en la misma base de datos 2 vistas con el mismo nombre, ni una vista
con el mismo nombre que una tabla.
- No se pueden crear vistas sobre tablas temporales
- No se pueden definir triggers asociados a una vista
- En una vista no puede haber 2 campos con el mismo nombre

12.1. Creación de una vista

Debemos tener en cuenta que en una vista no puede haber 2 nombres de columna iguales,
esto es relevante cuando se hacen Joins entre varias tablas donde coinciden algunos de los
campos.
Por ejemplo dada la siguiente estructura:

Tabla: provincias Tabla: comunidades

Queremos tener una vista con los siguientes campos:


De la tabla provincias:
- cod_provincia
- nom_provincia
- cod_comunidad
- observaciones

De la tabla comunidades:
- nom_comunidad
- observaciones

Uniremos las tablas a través de “cod_comunidad”.


Si creamos una vista con todos los campos mediante la siguiente sentencia:

43
CREATE VIEW vista_datos_completos_provincia AS
SELECT *
FROM provincias T1
INNER JOIN comunidades T2
ON T1.cod_comunidad = T2.cod_comunidad
ORDER BY nom_provincia;

Estaríamos creando una vista de nombre “view_datos_completos_provincia”, pero nos daría un


error, porque estamos intentando crear una vista con 2 campos con el mismo nombre
(“observaciones” y “cod_comunidad”), y nos interesa tener las observaciones tanto a nivel de
provincia como se comunidad, para ello utilizaremos alias, de tal forma que la sentencia correcta
sería:

CREATE VIEW vista_datos_completos_provincia AS


SELECT
T1.cod_provincia,
T1.nom_provincia,
T1.cod_comunidad,
T1.observaciones as observacion_provincia,
T2.nom_comunidad,
T2.observaciones as observacion_comunidad
FROM provincias T1
INNER JOIN comunidades T2
ON T1.cod_comunidad = T2.cod_comunidad
ORDER BY nom_provincia;

Posteriormente, podemos lanzar una sentencia SQL sobre la vista como si se tratara de una
tabla, sólo que dicha tabla contendría todos los datos que hemos mencionado anteriormente y
ordenados por el nombre de la provincia (es como hacer una select de una select).

Se pueden insertar y modificar datos a través de vistas si éstas son sencillas, no poseen clausulas
group by, having, etc. Y en muchos gestores no se aceptan en joins.

Las vistas se usan en consultas, no se deben utilizar indiscriminadamente porque sobrecarga al


gestor de base de datos. Se utilizan para que un usuario no administrador, sólo tenga acceso a
actualizar o insertar determinados datos en una tabla (se crea una vista con los campos que se
puede utilizar, se le da al usuario permisos sobre la vista y se le quitan sobre la tabla).

12.2. Borrado de una vista

DROP VIEW vista_datos_completos_provincia;


Elimina de la base de datos actual, la vista “vista_datos_completos_provincia”

44
12.3. Modificación de una vista

ALTER VIEW vista_datos_completos_provincia AS


SELECT
T1.cod_provincia,
T1.nom_provincia,
T1.observaciones as observacion_provincia,
T2.nom_comunidad,
T2.observaciones as observacion_comunidad
FROM provincias T1
INNER JOIN comunidades T2
ON T1.cod_comunidad = T2.cod_comunidad
ORDER BY nom_provincia;

En este caso hemos eliminado (con respecto al create view) el campo cod_comunidad de la tabla
de provincias en la presentación del resultado. Nótese que no es como en las tablas, debemos
definir nuevamente la vista, la ventaja frente a un DROP y un nuevo CREATE es el mismo que
con respecto a otro tipo de estructuras, que se mantienen los permisos.

45
13. Triggers

Los triggers son disparadores asociados a una tabla, se trata de operaciones que se ejecutan
automáticamente cuando se lanza sobre la base de datos, una sentencia de Inserción, actualiza-
ción o borrado de registros en una tabla.
Los triggers se almacenan a nivel de tabla de la misma forma que las columnas, los índices y las
claves foráneas.
** Aunque se almacenan a nivel de tabla, no pueden haber 2 triggers con el mismo nombre
aunque estén en distintas tablas.

El tipo de eventos puede ser:


BEFORE INSERT
BEFORE DELETE
BEFORE UPDATE
AFTER INSERT
AFTER DELETE
AFTER UPDATE

13.1. Creación de un trigger

Dada la siguiente tabla de ventas

1) Queremos que cuando se modifique un registro en la tabla de ventas, se recalcule


automáticamente el campo importe_total como precio_unitario * unidades_vendidas. para
ello crearemos un trigger.

DELIMITER $$;
CREATE TRIGGER trigger_actualiza_importetotal
BEFORE UPDATE ON ventas
FOR EACH ROW
BEGIN
IF NEW.unidades_vendidas <> OLD.unidades_vendidas OR NEW.precio_unitario <>
OLD.precio_unitario

46
THEN
SET NEW.importe_total = NEW.unidades_vendidas * NEW.precio_unitario;
END IF;
END $$;

Este trigger se lanza cada vez que se actualiza un registro en la tabla ventas, si se han
modificado las unidades_vendidas o el precio_unitario, se calcula el importe total,
grabándole en dicho campo el resultado de multiplicarlos.

2) Queremos que cuando se inserte un registro en la tabla de ventas, anteriormente descrita,


se incremente en 1 el campo “total_ventas” de la tabla “control_ventas_vendedores” para
el vendedor correspondiente a la nueva venta realizada.

La estructura de la tabla “control_ventas_vendedores” es:

DELIMITER $$;
CREATE TRIGGER trigger_nueva_venta
AFTER INSERT ON ventas
FOR EACH ROW
BEGIN
UPDATE control_ventas_vendedores SET control_ventas_vendedores.total_ventas =
control_ventas_vendedores.total_ventas + 1
WHERE control_ventas_vendedores.id_ven = NEW.id_ven;
END $$;

3) Dadas las siguientes tablas:

Tabla: personas

Tabla: contador

47
Tabla: movimientos

Queremos desarrollar 2 triggers:

trigger_actualiza_contador: Asociado a la tabla “personas”, cuando damos de alta una


persona con un nif determinado en la tabla “personas”, el trigger da de alta en la tabla
“contador” un registro para dicho nif, indicando que “num_movimientos” = 0.

trigger_actualiza_saldo: Asociado a la tabla “movimientos”, cuando damos de alta un


movimiento para un determinado nif en la tabla “movimientos”, el trigger accede a la tabla
“contador” e incrementa en una unidad el campo “num_movimientos” para dicho nif.
El trigger accede también a la tabla “personas” y actualiza para dicho nif el campo “saldo”,
de tal forma que; si en el campo “ingreso_gasto” de la tabla “movimientos” estamos
introduciendo “G” (Gasto), el “importe” que estamos indicando se resta al saldo en la tabla
de personas para dicho Nif, en caso contrario se suma.

trigger_actualiza_contador:

DELIMITER $$
DROP TRIGGER IF EXISTS trigger_actualiza_contador;
CREATE TRIGGER trigger_actualiza_contador AFTER INSERT ON personas
FOR EACH ROW
BEGIN
INSERT INTO base06.contador VALUES (new.nif, 0);
END
$$

trigger_actualiza_saldo:

DELIMITER $$
DROP TRIGGER IF EXISTs base06.trigger_actualiza_saldo;
CREATE TRIGGER base06.trigger_actualiza_saldo AFTER INSERT ON movimientos
FOR EACH ROW
BEGIN
declare wimporte int;
set wimporte = new.importe;
UPDATE CONTADOR SET num_movimientos = num_movimientos + 1 WHERE nif = new.nif;
if new.ingreso_gasto = 'G' THEN
set wimporte = wimporte*-1;
end if;
UPDATE PERSONAS SET saldo = wimporte where nif = new.nif;

48
END
$$

13.2. Borrado de un trigger

DROP TRIGGER trigger_actualiza_importetotal;

13.3. Modificación de un trigger

La modificación de un trigger se puede realizar mediante ALTER trigger, en algunos sistemas


gestores de bases de datos como SQL Server, en MySQL no se puede realizar, se debe borrar y
volver a crear.

49
14. Procedimientos

Programas SQL almacenados en base de datos que realizan un conjunto de tareas. Al contrario
que los triggers, no se encuentran asociados a una tabla sino que tienen la misma jerarquía.
- Pueden recibir y devolver parámetros
- Admiten recursividad

14.1. Procedimiento 1 - obtener_ventas_por_vendedor()

Dada la tabla de ventas:

Desarrollaremos un procedimiento que devuelva las ventas realizadas por cada vendedor

DELIMITER ##
CREATE PROCEDURE obtener_ventas_por_vendedor()
BEGIN
SELECT id_ven, sum(unidades_vendidas) FROM ventas GROUP BY id_ven;
END ##
DELIMITER ;

“Delimiter” indica que el bloque se debe ejecutar hasta encontrar ## (puede ser cualquier
cadena), al final volvemos a dejar el delimiter a “;” que es el que utiliza MySQL para finalizar
sentencia.

50
Llamamos ahora al procedimiento:

Call obtener_ventas_por_vendedor() o bien Call obtener_ventas_por_vendedor


El resultado de la ejecución es:

14.2. Procedimiento 2 - comparar_ventas()

Dada la tabla de ventas anterior, desarrollaremos un procedimiento al que le pasaremos como


parámetro el código de 2 empleados y devolverá el empleado de los 2 que ha vendido más
unidades de cualquier producto; en el caso que ambos hayan vendido lo mismo, el
procedimiento debe indicarlo.

DELIMITER ##
CREATE PROCEDURE comparar_ventas(in id_ven1 int, in id_ven2 int, out resultado
varchar(60))
BEGIN
DECLARE wventas1, wventas2 INT;
set wventas1 = 0;
set wventas2 = 0;
set resultado = '';

SELECT sum(unidades_vendidas) into wventas1 FROM ventas where id_ven = id_ven1;


SELECT sum(unidades_vendidas) into wventas2 FROM ventas where id_ven = id_ven2;
IF wventas1 > wventas2 THEN
set resultado = concat('ha vendido más el vendedor: ', id_ven1, ' con un total de: ',
wventas1);
ELSE

IF wventas1 < wventas2 THEN


SET resultado = CONCAT('ha vendido más el vendedor: ', id_ven2, ' con un total de: ',
wventas2);
ELSE

51
SET resultado = CONCAT('Los vendedores: ', id_ven1, ' y ', id_ven2, ' han vendido las
mismas unidades');
END IF;

END IF;

END ##
DELIMITER ;

Set lo utilizamos para asignar valores a una variable, si es interna al procedimiento y no es un


parámetro, la debemos definir con DECLARE
Llamamos ahora al procedimiento:
call comparar_ventas(1,2,@resul);
select @resul;

@ La utilizamos para indicar que es un parámetro de salida que nos devuelve el procedimiento.
El resultado de la ejecución es:

Llamamos al procedimiento con otros identificadores:


call comparar_ventas(1,6,@resul);
select @resul;
El resultado de la ejecución es:

Llamamos al procedimiento con 2 identificadores que han vendido las mismas unidades:
call comparar_ventas(1,4,@resul);
select @resul;
El resultado de la ejecución es:

14.3. Procedimiento 3 - listar comunidades()

Leer la tabla de comunidades autónomas y mostrar mediante un cursor el contenido de dicha


tabla, mostrar registro a registro con sus cabeceras correspondientes y mostrarlos todos juntos.

52
Contenido tabla comunidades Definción tabla de comunidades

Resultado

a) Solución 1 - Usaremos LOOP para recorrer el cursor

DELIMITER $$
DROP PROCEDURE IF EXISTS listar_comunidades;
CREATE PROCEDURE listar_comunidades()

BEGIN
DECLARE wcodigo VARCHAR(2);
DECLARE wnombre VARCHAR(45);
DECLARE wtodo VARCHAR(1000);
DECLARE final BOOLEAN DEFAULT false; -- Variable de control de fin de lectura del cursor

DECLARE cursor1 CURSOR FOR SELECT cod_comunidad, nom_comunidad FROM


comunidades;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET final = TRUE;

SET wtodo = '';

OPEN cursor1;

53
bucle1: LOOP
FETCH cursor1 INTO wcodigo, wnombre;
IF final = TRUE THEN
LEAVE bucle1;
END IF;

SET wtodo = CONCAT(wtodo, '\n', wcodigo, ' - ', wnombre);

SELECT
wcodigo AS 'codigo de comunidad',
wnombre AS 'nombre de comunidad'
FROM comunidades WHERE cod_comunidad = wcodigo;

END LOOP bucle1;


CLOSE cursor1;
/* Aquí mostramos el contenido de la consulta que hemos concatenado en wtodo con un
retorno de carro por cada select */
SELECT wtodo;
END $$

DELIMITER ;

b) Solución 2 - Usaremos WHILE para recorrer el cursor

DELIMITER $$
DROP PROCEDURE IF EXISTS listar_comunidades;
CREATE PROCEDURE listar_comunidades()

BEGIN
DECLARE wcodigo VARCHAR(2);
DECLARE wnombre VARCHAR(45);
DECLARE wtodo VARCHAR(1000);
DECLARE final BOOLEAN DEFAULT false; -- Variable de control de fin de lectura del cursor

54
DECLARE cursor1 CURSOR FOR SELECT cod_comunidad, nom_comunidad FROM
comunidades;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET final = TRUE;

SET wtodo = '';


OPEN cursor1;

FETCH cursor1 INTO wcodigo, wnombre;


WHILE final = FALSE DO
SET wtodo = CONCAT(wtodo, '\n', wcodigo, ' - ', wnombre);

SELECT
wcodigo AS 'codigo de comunidad',
wnombre AS 'nombre de comunidad'
FROM comunidades WHERE cod_comunidad = wcodigo;

FETCH cursor1 INTO wcodigo, wnombre;


END WHILE;

CLOSE cursor1;
/* Aquí mostramos el contenido de la consulta que hemos concatenado en wtodo
con un retorno de carro por cada select */
SELECT wtodo;
END $$

DELIMITER ;

14.4. Procedimiento 3 – listado de televisores con cálculo de totales

El siguiente procedimiento lee la tabla de televisores y graba en un fichero los datos de los
televisores agrupando por pulgadas, indicando los precios totales de todos los televisores por
su tamaño en pulgadas.

55
El procedimiento genera un fichero con la siguiente estructura:

Modo de ejecución:

CALL listar_televisores('listado de televisores',@result);


select @result;

Pasamos al procedimiento el literal que queremos aparezca como título del listado.
DELIMITER $$
DROP PROCEDURE IF EXISTS listar_televisores;
CREATE PROCEDURE listar_televisores(in par1_titulo varchar(100), out mensaje_fin
varchar(100))

-- Comienzo programa

BEGIN
DECLARE wpulgadas int;
DECLARE wpulgadas_ant int;

56
DECLARE wmarca varchar(30);
DECLARE wmodelo varchar(30);
DECLARE wprecio_unidad double;
DECLARE wnumero_unidades double;
DECLARE wprecio_total double;
DECLARE wtextofichero VARCHAR(10000);
DECLARE final BOOLEAN DEFAULT false;
DECLARE wtotalreg integer;
DECLARE cursor1 CURSOR FOR SELECT pulgadas, marca, modelo, precio_unidad,
numero_unidades FROM televisores order by pulgadas;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET final = TRUE;

-- Inicializamos variables de trabajo

SET wpulgadas_ant = 0;
SET wprecio_total = 0;
SET wtotalreg = 0;

-- Abrimos cursor y leemos primer registro

OPEN cursor1;
FETCH cursor1 INTO wpulgadas, wmarca, wmodelo, wprecio_unidad, wnumero_unidades;
IF final = FALSE THEN
SET wpulgadas_ant = wpulgadas;
SET wtextofichero = CONCAT(par1_titulo,'\r');
SET wtextofichero = CONCAT(wtextofichero,'----------------------------------------------\r\r');
SET wtextofichero = CONCAT(wtextofichero,'-> Pulgadas: ',wpulgadas,'\r');
END IF;

-- Procesamos hasta fin de cursor

WHILE final = FALSE DO

-- Ruptura por cambio de pulgadas

IF wpulgadas != wpulgadas_ant THEN


SET wtextofichero = CONCAT(wtextofichero,'Precio Total Televisores: ', wprecio_total, '\r\r');
SET wprecio_total = wprecio_unidad * wnumero_unidades;
SET wpulgadas_ant = wpulgadas;
SET wtextofichero = CONCAT(wtextofichero,'-> Pulgadas: ',wpulgadas,'\r');
ELSE
SET wprecio_total = wprecio_total + (wprecio_unidad * wnumero_unidades);
END IF;

SET wtextofichero = CONCAT(wtextofichero, 'Marca: ', wmarca, ' Modelo: ', wmodelo, '
Precio: ', wprecio_unidad * wnumero_unidades,'\r');
FETCH cursor1 INTO wpulgadas, wmarca, wmodelo, wprecio_unidad, wnumero_unidades;

END WHILE;

57
SET wtextofichero = CONCAT(wtextofichero,'Precio Total Televisores: ', wprecio_total, '\r');

-- Volcamos en "c:/desarrollo/pulgada.txt" los datos de los televisores

SELECT wtextofichero INTO OUTFILE 'c:/desarrollo/pulgadas.txt' FROM televisores limit 1;


CLOSE cursor1;

-- Calculamos total de registros leidos para devolverlo en el output del procedimiento

select count(*) into wtotalreg from televisores;


set mensaje_fin = CONCAT('El listado ha procesado un total de: ', wtotalreg, ' registros');

END $$

14.5. Procedimiento 4 – Marca con televisor más caro

Este procedimiento, recibe como parámetro 2 marcas, y devuelve la marca que tiene el televisor
más caro. Si las 2 marcas tienen el mismo precio de televisor más caro, lo indica y si las marcas
no se encuentran en la tabla de televisores, también lo indica.

Modo de ejecución:

call televisor_mas_caro('LG','SONY',@otroresultado);
Select @otroresultado;

Pasamos al procedimiento las 2 marcas, usaremos la estructura ELSEIF para el desarrollo.


DELIMITER $$
DROP PROCEDURE IF EXISTS televisor_mas_caro;
CREATE PROCEDURE televisor_mas_caro(in par_marca1 varchar(30), par_marca2 varchar(30),
out par_marca_cara varchar(30))

-- Comienzo programa

BEGIN
DECLARE wpreciomax1 double;
DECLARE wpreciomax2 double;

-- Inicializamos variables de trabajo

SELECT max(precio_unidad) into wpreciomax1 from televisores where marca = par_marca1;


SELECT max(precio_unidad) into wpreciomax2 from televisores where marca = par_marca2;

IF wpreciomax1 = wpreciomax2 THEN


set par_marca_cara = 'Ambas marcas tienen el mismo precio mayor';
ELSEIF wpreciomax1 > wpreciomax2 THEN
set par_marca_cara = par_marca1;
ELSE
set par_marca_cara = par_marca2;

58
END IF;

END $$

14.6. Eliminación de un procedimiento

Para borrar un procedimiento, ejecutaremos:

DROP PROCEDURE comparar_ventas;

59
15. Funciones

Programas SQL almacenados en base de datos que realizan un conjunto de tareas. No se


encuentran asociadas a una tabla sino que tienen la misma jerarquía.
- No son llamadas mediante call, se ejecutan desde sentencias SQL.
E: SELECT Campo1, funcion1(<argumentos>); WHERE funcion1() = ‘xxx’
- Obligatoriamente deben retornar un valor mediante el uso de la cláusula RETURNS

15.1. Función 1 – listado de televisores con cálculo de totales

La siguiente función, retorno el precio más caro de un televisor cuya marca se pasa como
parámetro a la función.
Usaremos dicha función para mostrar los datos de aquellos televisores, que sean más caros
que el televisor más caro de la marca que se seleccione.
Sentencia de llamada a la función:
SELECT * FROM televisores where precio_unidad > precio_max_marca('XIAOMI');
Código de la función
DELIMITER $$
DROP FUNCTION IF EXISTS Precio_Max_Marca;
CREATE FUNCTION Precio_Max_Marca(par_marca varchar(30))
RETURNS DOUBLE
BEGIN
DECLARE wprecio double;
SELECT MAX(precio_unidad) INTO wprecio FROM TELEVISORES WHERE MARCA = par_marca;
RETURN wprecio;
END
$$

15.2. Función 2 – listado de televisores indicando las pulgadas en


carácter

La siguiente función, muestra las pulgadas en número, 35,45,55,65 de un televisor, de la tabla


de televisores, salvo que las pulgadas sean 55, 65 o 75 que devolverá “Cincuenta y cinco”,
“Sesenta y cinco” y “Setenta y cinco”.
Recibirá como parámetro las pulgadas del televisor.

Sentencia de llamada a la función:


select marca, modelo, convertir_pulgadas(pulgadas) from televisores;

60
Código de la función
DELIMITER $$
DROP FUNCTION IF EXISTS convertir_pulgadas;
CREATE FUNCTION convertir_pulgadas(par_pulgadas int)
RETURNS varchar(30)
BEGIN
DECLARE wretorno VARCHAR(30);
CASE par_pulgadas
WHEN 55 THEN RETURN 'Cincuenta y cinco';
WHEN 65 THEN RETURN 'Sesenta y cinco';
WHEN 75 THEN RETURN 'Setenta y cinco';
ELSE RETURN par_pulgadas;
END CASE;
END
$$

61
16. ANEXOS

16.1. Vistas del sistema

Las vistas del sistema de MySQL nos permiten consultar información sobre la estructura de las
bases de datos. Dichas vistas se encuentran en una base de datos denominada
“information_schema”.
Dentro de esta base de datos tenemos aproximadamente 80 vistas de control de sólo lectura
que nos permiten conocer todos los elementos creados en todas las bases de datos.

Ejemplo1: Queremos conocer los índices que tiene una tabla concreta de una base de datos
determinada (por ejemplo tabla “provincias” de la base “base01”, podemos utilizar la
instrucción “Show index from provincias”

Pero también podemos hacer lo siguiente:


1) Accedemos a la base de datos: “Information_Schema”, esta base de datos es la que tiene
las tablas del sistema.
Use Information_Schema;
2) Vemos cual es el identificador de tabla que nos interesa, para ello consultamos el maestro
de tablas: “INNODB_SYS_tables” (ojo que esto depende del formato de creación de la tabla)
Select * from INNODB_SYS_tables where NAME like ('%provincias%’)

Evidentemente Podemos buscar directamente la tabla de provincias de la base01,


cambiando la sentencia Select anterior.
3) Con el identificador de la tabla (167) accedemos a “INNODB_SYS_INDEXES” y obtengo los
indices
select * from INNODB_SYS_INDEXES where TABLE_ID = 167

Ejemplo2: Queremos conocer las diferentes claves de una tabla (por ejemplo queremos saber
las claves ajenas y la clave primaria definidas en la tabla “coches” perteneciente a la base de
datos “base02”).

62
Para ello lanzaremos la siguiente consulta:
Use Information_Schema;
SELECT * FROM TABLE_CONSTRAINTS
WHERE TABLE_CONSTRAINTS.TABLE_SCHEMA = 'base02'
AND TABLE_CONSTRAINTS.TABLE_NAME = 'coches';

La existencia de estas vistas es de gran ayuda para los administradores de bases de datos, no
necesitando el uso de instrucciones “show” para la obtención de detalles de la estructura de las
bases de datos.
Los usuarios no administradores, también tienen acceso a estas vistas, pero sólo a los registros
de aquellos elementos a los que tienen acceso.
Para obtener más información sobre el contenido de cada una de las vistas podemos acceder al
site oficial de MySQL, en concreto a:
https://dev.mysql.com/doc/refman/8.0/en/information-schema.html

16.2. JS

shell.options.set('resultFormat', 'json') (Si queremos que nos devuelva los datos en formato
JSON) hay varios tipos de formato JSON
shell.options.set('resultFormat', 'table') (Si queremos que nos devuelva los datos en formato
tabla)
session.runSql('select * from base01.provincias'); (nos muestra el contenido de la table
provincias)

16.3. Redireccionamiento de consultas a fichero

Para las sentencias SQL que lancemos con la shell, podemos redirigir su salida a un fichero en
vez de a la pantalla.
Ejemplo con la instrucción select.
Si la sentencia no la ejecutamos con el usuario root, al usuario le debemos dar permiso para
generar ficheros:
GRANT FILE ON *.* TO 'usuario'@'localhost' ;
SELECT * INTO OUTFILE 'c:/desarrollo/temp.txt' FROM provincias; (no se pueden poner comillas
dobles), si el fichero ya existe la consulta da error.

63
Por omisión la separación entre campos se realiza en el fichero de salida, con tabuladores, pero
esto se puede cambiar:
SELECT * INTO OUTFILE 'c:/desarrollo/temp2.txt' FIELDS TERMINATED BY ',' OPTIONALLY
ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM provincias;
Separa lo campos por una coma, y añade comillas dobles al principio y final de cada campo.
Ejemplo:

Si quitamos la cláusula enclosed by:

Si quitamos LINES TERMINATED BY \n, el resultado es el mismo porque por omisión ya incorpora
un retorno de carro por cada registro. Ahora bien, si se añade este parámetro, pero en vez de
poner ‘\n’ se pone cualquier otro carácter o conjunto de caracteres, entonces ya no haría el salto
de línea, aparecería todo en una línea con dichos caracteres separando los registros.

16.4. Ejecución de ficheros .sql

Si no queremos copiar a la shell, el contenido SQL de un fichero, para su ejecución, podemos


ejecutar directamente el fichero mediante la instrucción:
source '<path completo del dichero> '
Ejemplo:
source ‘c:/desarrollo0/ejecuta.sql’
No es necesario que la extensión del fichero sea .sql, pero sí que sea tipo texto

16.5. Otros comandos de interés

SHOW CREATE TABLE coches


Permite obtener la sentencia que genera una tabla tal y como se encuentra definida en la
actualidad (creación y ejecución de Alter posteriores)

64
Podemos ver los campos y sus características, la clave primaria y la clave ajena con la tabla
propietarios por el campo “nif_propietario”.

CREATE TABLE provincias2 SELECT * FROM provincias;


Crea la tabla provincias2 con la misma estructura que la tabla provincias e inserta sus datos.

CREATE TABLE provincias2 LIKE provincias;


Crea la tabla provincias2 con la misma estructura que la tabla provincias.

INSERT INTO provincias2 SELECT * FROM provincias;


Inserta los datos de la tabla provincias en la tabla provincias2;

65

También podría gustarte