SQL - MySQL - Trimestre 3
SQL - MySQL - Trimestre 3
BASES DE DATOS
MySQL al 99%
Curso 2022-2023
INDICE
3. BORRADO DE TABLAS.............................................................................................. 9
2
5.3. Campos autoincrementales ...................................................................... 18
8. TRANSACCIONES................................................................................................... 23
9. SELECT ................................................................................................................. 25
3
11. SENTENCIAS DCL ................................................................................................ 40
12. VISTAS................................................................................................................ 43
16. ANEXOS.............................................................................................................. 62
16.2. JS........................................................................................................... 63
4
16.4. Ejecución de ficheros .sql ....................................................................... 64
5
1. Creación de bases de datos
6
2. Creación de tablas
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));
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:
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.
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.
Podemos renombrar una tabla de 2 formas, por ejemplo vamos a renombrar la tabla
“empleados” y la vamos a llamar “usuarios”
Borramos varios campos (no contemplamos posibilidad de integridad con otras tablas)
alter table empleados drop column edad, drop column fecha_alta;
10
4.4. Renombrar campos
En la tabla ventas añadimos un índice que ordena la tabla ascendentemente por el campo
stock:
11
4.9. Crear claves ajenas
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”
CASCADE
12
SET NULL
NO ACTION
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.
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.
14
5. Inserción de 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)
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
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
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:
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;
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;
20
7. Actualización de registros
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:
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
23
commit
rollback
<desconectar>
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
La sentencia Select permite consultar determinados datos de una tabla, permitiendo realizar
operaciones con ellos:
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.
27
9.5. Utilizar operadores y funciones en el apartado SELECT
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).
28
SELECT MAX(precio) FROM coches; (muestra el precio más alto de la tabla)
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.
➢ 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
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.
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";
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;
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).
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:
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:
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:
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.
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:
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.
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.
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
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”
40
4) Damos permisos al usuario1 para que pueda realizar cualquier operación sobre la tabla
“ventas” de la base de datos “base01”
5) Damos permisos al usuario1 para que pueda realizar determinada operativa sobre la tabla
“ventas” de la base de datos “base01”
11.2. Revoke
Algunas de estas sentencias no funcionan sobre XAMPP pero si sobre un MySQL Nativo.
41
2) Quitamos todos los permisos para la base de datos “base01” al usuario1
4) Quitamos algunos permisos para la base de datos “base01” tabla “ventas” al usuario1
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
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:
De la tabla comunidades:
- nom_comunidad
- observaciones
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;
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.
44
12.3. Modificación de una vista
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.
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.
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 $$;
Tabla: personas
Tabla: contador
47
Tabla: movimientos
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
$$
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
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:
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 = '';
51
SET resultado = CONCAT('Los vendedores: ', id_ven1, ' y ', id_ven2, ' han vendido las
mismas unidades');
END IF;
END IF;
END ##
DELIMITER ;
@ 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 2 identificadores que han vendido las mismas unidades:
call comparar_ventas(1,4,@resul);
select @resul;
El resultado de la ejecución es:
52
Contenido tabla comunidades Definción tabla de comunidades
Resultado
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
OPEN cursor1;
53
bucle1: LOOP
FETCH cursor1 INTO wcodigo, wnombre;
IF final = TRUE THEN
LEAVE bucle1;
END IF;
SELECT
wcodigo AS 'codigo de comunidad',
wnombre AS 'nombre de comunidad'
FROM comunidades WHERE cod_comunidad = wcodigo;
DELIMITER ;
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;
SELECT
wcodigo AS 'codigo de comunidad',
wnombre AS 'nombre de comunidad'
FROM comunidades WHERE cod_comunidad = wcodigo;
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 ;
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:
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;
SET wpulgadas_ant = 0;
SET wprecio_total = 0;
SET wtotalreg = 0;
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;
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');
END $$
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;
-- Comienzo programa
BEGIN
DECLARE wpreciomax1 double;
DECLARE wpreciomax2 double;
58
END IF;
END $$
59
15. Funciones
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
$$
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
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”
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)
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 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.
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”.
65