Académique Documents
Professionnel Documents
Culture Documents
PRIMERO DE MAYO
Tecnología Superior en Desarrollo de Software
GUÍA DE ESTUDIO
Autor:
Ing. Diego Jhonatan Chamba Saca
Yantzaza – Ecuador
Contenido
UNIDAD 1. SENTENCIAS DDL Y DML ......................................................................................... 4
1.1. CONCEPTOS BÁSICOS ............................................................................................... 8
1.2 Lenguaje de Definición de datos DDL ................................................................................. 8
1.3. Lenguaje de Manipulación de datos DML ......................................................................... 13
1.4. Sentencias select .............................................................................................................. 15
1.5. Uso de where, order by, group by, sum, limit ................................................................... 17
1.6 Funciones de agrupamiento (count - max - min - sum - avg) ............................................ 18
UNIDAD II Implementación de Índices, Trigger y vistas .............................................................. 27
2.1. Introducción, Entorno y uso de índices ............................................................................. 27
2.2. TIPOS Y ESTRUCTURA DE ÍNDICES ............................................................................. 28
2.3. CREACIÓN Y ELIMINACIÓN DE TRIGGERS ................................................................. 31
2.4. USO DE VISTAS Y SINTAXIS .......................................................................................... 41
2.5. VENTAJAS Y USO DE VISTAS........................................................................................ 43
UNIDAD III PROCEDIMIENTOS ALMACENADOS, INDICES Y CURSORES ........................... 45
3.1 Procedimientos almacenados y Tablas de Permisos ........................................................ 45
3.2 Introducción a índices ........................................................................................................ 50
3.3. Bucles y Cursores ............................................................................................................. 51
UNIDAD IV TRANSACCIONES, CONCURRENCIAS Y SEGURIDAD DE BASE DE DATOS .. 62
4.1. Introducción a transacciones ......................................................................................... 62
4.2. Lecturas Consistentes .................................................................................................... 70
4.3. Aplicación de Lecturas Consistentes ............................................................................. 72
4.4. Transacciones ................................................................................................................ 75
4.5. Control de Concurrencias .............................................................................................. 76
4.6. Control de concurrencias por DBMS ............................................................................. 77
4.7. Ejemplo de Transacciones por concurrencias ............................................................... 78
4.8. Tipos de Usuario ............................................................................................................ 92
4.9. Implementación de políticas de seguridad ..................................................................... 93
4.10. Aplicación ..................................................................................................................... 94
Bibliografía ................................................................................................................................... 95
Índice de Tablas
Tabla 1: Ejemplo de transacciones .............................................................................................. 79
3
PERFIL DE LA CARRERA
5
INTRODUCCIÓN.
La asignatura comienza con un tema que tiene como objetivo introducir aspectos
avanzados relacionados con las bases de datos. A continuación, se explica el
procesamiento de transacciones, el control de la concurrencia y las técnicas de
recuperación, además de descripciones de cómo se materializan estos
conceptos en SQL (Structured Query Language). Tras el estudio de las
transacciones se presentan modelos avanzados como las bases de datos
orientadas a objetos y las bases de datos distribuidas. Seguidamente, se
explican varios temas relacionados con el análisis de información en bases de
datos y la extracción de conocimiento a partir de éstas. Finalmente se presenta
XML, una forma alternativa de estructuración de la información, y se introducen
las principales tecnologías y aplicaciones emergentes en la materia.
OBJETIVO GENERAL DE LA ASIGNATURA.
7
UNIDAD 1. SENTENCIAS DDL Y DML
(Java, 2010) Las sentencias SQL se dividen en dos categorías; Lenguaje de definición de
datos; data definition language (DDL) y Lenguaje de manipulación de datos; data
manipulation language (DML).
Tras crear una base de datos los tipos de dato que podemos guardar son:
Numéricos
De fecha
Tipo string
Otras sentencias para trabajar con tablas son:
TRUNCATE TABLE
DROP TABLE
MySQL SELECT
ALTER TABLE
MySQL INSERT
RENAME TABLE
Veamos a las diferentes sintaxis que tenemos tener en la creación de una tabla extraídas de
su web oficial.
Con el código superior tenemos la sentencia estándar para crear la tabla, solamente tenemos
que poner el nombre de la tabla, nombre de la columna y su tipo.
Podemos tener una base de datos con numerosas tablas, por lo que al crear una nueva
podemos tener una existente con el mismo nombre. Para evitar problemas debemos usar la
sentencia ‘IF NOT EXIST‘:
PRIMARY KEY: Solo se puede crear una primary key por tabla, es la clave primaria
que identifica de manera única cada registro/fila de la tabla. Por ejemplo, el documento
de identidad DNI de una persona.
INDEX|KEY: Ambas son sinónimas, puede haber una o varias. Establecen los índices de
la tabla con los cuales se pueden agilizar las búsquedas en la base de datos. De esta
manera se evita la búsqueda de un parámetro por cada columna de la tabla. Es como un
índice de un libro con el que nos evitamos recorrer cada página.
9
UNIQUE: Es una restricción por la cual el valor de dicha columna debe ser único y diferente
al del valor de dicha columna de resto de registros. Por ejemplo, se suele usar con las
columnas declaradas como primary key.
FULLTEXT: Es un índice que solo funciona con las columnas con formato char, varchar,
text y con almacenamiento MyISAM. Este índice facilita las grandes búsquedas sobre
texto y realiza automáticamente comparaciones de texto sobre una cadena dada. Realiza
búsquedas más afinadas que la sentencia LIKE. Se ignoran las palabras con menos de 4
letras y las palabras que aparezcan en más del 50% de los registros.
FOREIGN KEY: Clave foránea, es un índice por el cual podemos relacionar 2 tablas. Este
valor debe existir en ambas tablas, por ejemplo, el código postal de la tabla ‘usuarios’ y la
tabla ‘población’.
TIPOS DE DATOS
BIT[(length)]
TINYINT[(length)] [UNSIGNED] [ZEROFILL]
SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
INT[(length)] [UNSIGNED] [ZEROFILL]
INTEGER[(length)] [UNSIGNED] [ZEROFILL]
BIGINT[(length)] [UNSIGNED] [ZEROFILL]
REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL]
NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL]
DATE
TIME
TIMESTAMP
DATETIME
YEAR
CHAR[(length)] [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
VARCHAR(length) [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
BINARY[(length)]
VARBINARY(length)
TINYBLOB
BLOB
MEDIUMBLOB
LONGBLOB
TINYTEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
TEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
MEDIUMTEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
LONGTEXT [BINARY]
[CHARACTER SET charset_name] [COLLATE collation_name]
ENUM(value1,value2,value3,...)
[CHARACTER SET charset_name] [COLLATE collation_name]
SET(value1,value2,value3,...)
[CHARACTER SET charset_name] [COLLATE collation_name]
spatial_type
Ejemplo para crear una tabla en MySQL con CREATE TABLE
11
Aquí os pongo un ejemplo de una sentencia SQL para crear la tabla en una base de datos
MySQL:
Cambia la estructura de una tabla. Por ejemplo, agrega o elimina columnas, crea o elimina
índices, modificar el tipo de columnas existentes o renombrar columnas o la propia tabla.
También modifica las características tales como el tipo de almacenamiento utilizado para
las tablas. Otras sentencias para trabajar con tablas son:
Con la sentencia DROP TABLE de MySQL podemos borrar de manera rápida y sencilla una
tabla de una base de datos.
Sintaxis:
Esta es la sintaxis básica con la que si tenemos permisos para hacerlo…. borraríamos una tabla.
Podemos afinar la sentencia añadiendo ‘IF EXISTS‘, es decir si existe
De esta manera solo borraríamos la tabla si esta existe. Es recomendable usar ‘IF EXISTS‘ ya
que si la tabla no existe cortaría la ejecución del código MySQL restante.
Se pueden borrar varias tablas separando el nombre de cada una con una ‘,’.
TRUNCATE - elimina todos los registros de la tabla, incluyendo todos los espacios asignados a
los registros.
La sentencia TRUNCATE TABLE con la que podemos vaciar una tabla de una base de
datos MySQL
Sintaxis:
TRUNCATE TABLE nombre_tabla;
13
popular hoy día es SQL, usado para recuperar y manipular datos en una base de datos relacional.
Otros ejemplos de DML son los usados por bases de datos IMS/DL1, CODASYL u otras.
El lenguaje de manipulación de datos más popular hoy día es SQL, usado para recuperar y
manipular datos en una base de datos relacional. Otros ejemplos de DML son los usados por
bases de datos IMS/DL1, CODASYL u otras.
1- INSERT. - Una sentencia INSERT de SQL agrega uno o más registros a una (y sólo una) tabla
en una base de datos relacional.
2-UPDATE. - Una sentencia UPDATE de SQL es utilizada para modificar los valores de un
conjunto de registros existentes en una tabla.
3- DELETE
Una sentencia DELETE de SQL borra uno o más registros existentes en una tabla.
Ejemplo 1 (borro todos los valores de las columnas alumno y materia donde la materia sea spd2):
SELECT
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[HAVING where_condition]
[PROCEDURE procedure_name(argument_list)]
15
[INTO OUTFILE 'file_name'
export_options
En WHERE where_condition se especifican la o las condiciones que se deben cumplir para los
valores solicitados.
Dentro de la claúsula WHERE tenemos los siguientes condicionantes que son importantes y
útiles:
GROUP BY: Nos permite agrupar los datos obtenidos de la base de datos.
HAVING: Permite hacer cálculos y condiciones más complejas que no se pueden hacer con la
cláusula
WHERE.
Sintaxis:
‘>‘ El operador > determina si el primer valor es mayor que el segundo valor comparado.
‘<‘ El operador < determina si el primer valor es menor que el segundo valor comparado.
‘>=‘ El operador >= determina si el primer valor es mayor o igual que el segundo valor
comparado.
‘<=‘ El operador <= determina si el primer valor es menor o igual que el segundo valor
comparado.
Order By.
La cláusula de MySQL ORDER BY que tiene como finalidad ordenar los resultados de las
consultas por columnas en vez del campo índice por defecto.
Sintaxis:
Ejemplos:
17
1. SELECT * FROM nombre_tabla WHERE campo1 = condicionante ORDER BY
campo_ordenacion;
2. SELECT * FROM nombre_tabla ORDER BY campo_ordenacion1 DESC,
campo_ordenacion2 DESC;
3. SELECT * FROM nombre_tabla WHERE campo = condicionante ORDER BY
campo_ordenacion1 DESC, campo_ordenacion2 DESC;
4. SELECT * FROM nombre_tabla WHERE campo1 > condicionante ORDER BY
campo_ordenacion ASC;
5. SELECT * FROM nombre_tabla WHERE campo_ordenacion = condicionante AND
campo_ordenacion2 > condicionante2 ORDER BY campo_ordenacion;
6. SELECT * FROM empleados ORDER BY edad, antiguedad;
7. SELECT * FROM empleados WHERE sexo = 'mujer' ORDER BY edad;
8. SELECT * FROM empleados ORDER BY edad DESC, antiguedad DESC;
9. SELECT * FROM empleados WHERE sexo = 'hombre' ORDER BY antiguedad DESC,
edad DESC;
10. SELECT * FROM empleados WHERE edad > 35 ORDER BY nombre ASC;
11. SELECT * FROM empleados WHERE edad > 35 ORDER BY nombre ASC;
(Jairo, 2012) Existen en MySQL funciones que nos permiten contar registros,
calcular sumas, promedios, obtener valores máximos y mínimos. Ya hemos
aprendido "count()", veamos otras.
La función avg() retorna el valor promedio de los valores del campo especificado.
Por ejemplo, queremos saber el promedio del precio de los libros referentes a
"PHP":
Problema Resuelto:
Trabajamos con la tabla "libros" que registra la información de los libros que
vende una librería.
Creamos la tabla:
19
insert into libros (titulo,autor,editorial,precio,cantidad)
values('El aleph','Borges','Planeta',15,100);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Martin Fierro','Jose Hernandez','Emece',22.20,200);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Antologia poetica','J.L. Borges','Planeta',40,150);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Aprenda PHP','Mario Molina','Emece',18.20,200);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Cervantes y el quijote','Bioy Casares- J.L. Borges',
'Paidos',36.40,100);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Manual de PHP', 'J.C. Paez', 'Paidos',30.80,120);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Harry Potter y la piedra filosofal','J.K. Rowling',
'Paidos',45.00,50);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Harry Potter y la camara secreta','J.K. Rowling',
'Paidos',46.00,100);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Alicia en el pais de las maravillas','Lewis Carroll',
'Paidos',null,200);
Retorna 1220; verifique la suma, sumando los valores de todos los registros del
campo "cantidad".
Retorna 250; verifique el total sumando las cantidades de los libros cuya
editorial sea "Planeta".
Si queremos saber cuál es el mayor precio de los libros usamos:
Devuelve 46.
Verifiquemos lo anterior realizando una consulta ordenada por precio de forma descendente:
Retorna 45.
Solicitamos el promedio del precio de los libros que tratan sobre "PHP":
Retorna 24.50...
Problema Propuesto :
2- cree la tabla:
23
4- calcule la cantidad de inscriptos para el curso de
"Operador de PC":
25
D) Un comercio guarda la información de sus ventas en una
tabla llamada
"facturas" en la que registra el número de factura, la
descripción de los
items comprados, el precio por unidad de los items y la cantidad.
2- Cree la tabla:
(Amor, 2015)
Introducción
Entorno
Hardware:
MySQL emplea los índices para encontrar las filas que contienen los valores
específicos de las columnas empleadas en la consulta de una forma más rápida.
Si no existiesen índices, MySQL empezaría buscando por la primera fila de la
27
tabla hasta la última buscando aquellas filas que cumplen los valores
establecidos para las columnas empleadas en la consulta. Esto implica que,
cuantas más filas tenga la tabla, más tiempo tardará en realizar la consulta. En
cambio, si la tabla contiene índices en las columnas empleadas en la consulta,
MySQL tendría una referencia directa hacia los datos sin necesidad de recorrer
secuencialmente todos ellos.
Tipos de índices:
UNIQUE: este tipo de índice se refiere a un índice en el que todas las columnas
deben tener un valor único. Esto implica que no admite valores duplicados para
la columna (o columnas) que componen el índice. Aplica la restricción de que los
datos de la columna (o columnas) deben tener un valor único.
PRIMARY: este tipo de índice se refiere a un índice en el que todas las columnas
deben tener un valor único (al igual que en el caso del índice UNIQUE) pero con
la limitación de que sólo puede existir un índice PRIMARY en cada una de las
tablas. Aplica la restricción de que los datos de la columna (o columnas) deben
tener un valor único.
SPATIAL: estos índices se emplean para realizar búsquedas sobre datos que
componen formas geométricas representadas en el espacio. Este tipo de índices
sólo están soportados por InnoDB y MyISAM en MySQL 5.7.
29
el FULLTEXT (ya que este índice mira en TODAS las columnas que componen
el índice).
Para crear un índice, se empleará la siguiente estructura:
“CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name ON
table_name (index_col_name…) index_type;”
Donde:
index_name: es el nombre del índice.
table_name: es el nombre de la tabla donde se va a crear el índice.
index_col_name: nombre de la columna (o columnas) que formarán el índice.
index_type: es el tipo del índice. Se emplea con USING [BTREE | HASH].
Un ejemplo sería:
CREATE UNIQUE INDEX mi_indice_unico ON mi_tabla (mi_columna) USING
HASH;
Una vez hemos visto los tipos de índices, vamos a ver los distintos tipos de
estructuras que se pueden crear para almacenar los índices junto con las
características de cada uno de ellas:
B-TREE: este tipo de índice se usa para comparaciones del tipo =, >,
<, >=, <=, BETWEEN y LIKE (siempre y cuando se utilice sobre
constantes que no empiecen por %). Para realizar búsquedas
empleando este tipo de índice, se empleará cualquier columna (o
conjunto de columnas) que formen el prefijo del índice. Por ejemplo: si
un índice está formado por las columnas [A, B, C], se podrán realizar
búsquedas sobre: [A], [A, B] o [A, B, C].
HASH: este tipo de índice sólo se usa para comparaciones del tipo = o
<=>. Para este tipo de operaciones son muy rápidos en comparación a
otro tipo de estructura. Para realizar búsquedas empleando este tipo
de índice, se emplearán todas las columnas que componen el índice.
31
Un disparador es un objeto con nombre en una base de datos que se asocia con
una tabla, y se activa cuando ocurre un evento en particular para esa tabla.
El disparador queda asociado a la tabla nombre_tabla. Esta debe ser una tabla
permanente, no puede ser una tabla TEMPORARY ni una vista.
DELIMITER |
DELIMITER ;
35
La sentencia CREATE TRIGGER necesita el privilegio SUPER. Esto se agregó
en MySQL 5.0.2.
Utilización de disparadores
Un disparador se asocia con una tabla y se define para que se active al ocurrir
una sentencia INSERT,DELETE, o UPDATE sobre dicha tabla. Puede también
establecerse que se active antes o despues de la sentencia en cuestión. Por
ejemplo, se puede tener un disparador que se active antes de que un registro
sea borrado, o después de que sea actualizado.
Para crear o eliminar un disparador, se emplean las sentencias CREATE
TRIGGER y DROP TRIGGER. La sintaxis de las mismas se describe
en Sección 20.1, “Sintaxis de CREATE TRIGGER” y Sección 20.2, “Sintaxis
de DROP TRIGGER”.
Este es un ejemplo sencillo que asocia un disparador con una tabla para cuando
reciba sentencias INSERT. Actúa como un acumulador que suma los valores
insertados en una de las columnas de la tabla.
37
Para utilizar el disparador, se debe establecer el valor de la variable acumulador
a cero, ejecutar una sentencia INSERT, y ver qué valor presenta luego la
variable.
Las palabras clave OLD y NEW permiten acceder a columnas en los registros
afectados por un disparador. (OLD y NEW no son sensibles a mayúsculas). En
un disparador para INSERT, solamente puede utilizarse NEW.nom_col; ya que
no hay una versión anterior del registro. En un disparador paraDELETE sólo
puede emplearse OLD.nom_col, porque no hay un nuevo registro. En un
disparador para UPDATE se puede emplear OLD.nom_col para referirse a las
columnas de un registro antes de que sea actualizado, y NEW.nom_col para
referirse a las columnas del registro luego de actualizarlo.
Una columna precedida por OLD es de sólo lectura. Es posible hacer referencia
a ella pero no modificarla. Una columna precedida por NEW puede ser
referenciada si se tiene el privilegio SELECTsobre ella. En un
disparador BEFORE, también es posible cambiar su valor con SET
NEW.nombre_col =valor si se tiene el privilegio de UPDATE sobre ella. Esto
39
significa que un disparador puede usarse para modificar los valores antes que se
inserten en un nuevo registro o se empleen para actualizar uno existente.
mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
-> FOR EACH ROW
-> BEGIN
-> IF NEW.amount < 0 THEN
-> SET NEW.amount = 0;
-> ELSEIF NEW.amount > 100 THEN
-> SET NEW.amount = 100;
-> END IF;
-> END;//
mysql> delimiter ;
Podría parecer más fácil definir una rutina almacenada e invocarla desde el
disparador utilizando una simple sentencia CALL. Esto sería ventajoso también
si se deseara invocar la misma rutina desde distintos disparadores. Sin
embargo, una limitación de los disparadores es que no pueden utilizar CALL.
Se debe escribir la sentencia compuesta en cada CREATE TRIGGER donde se
la desee emplear.
(Barrena, ANER BARRENA, 2016) vamos a repasar la sentencia CREATE VIEW MySQL,
esta tiene como finalidad crear tablas virtuales a partir de consultas SELECT a otras tablas.
Las vistas de una base de datos MySQL tienen la misma estructura de filas y columnas de
una tabla, no puede haber una vista con el mismo nombre de una tabla.
41
CREATE [OR REPLACE] VIEW nombre_vista [column_list] AS consulta_SELECT
En el código superior estaríamos creando una vista con todas las filas y columnas de la tabla
futbolistas.
CREATE VIEW vista_futbolistas AS SELECT futbolistas.id, nombre, apellidos FROM
futbolistas INNER JOIN tarjetas_amarillas ON futbolistas.id = tarjetas_amarillas.id_futbolista;
En este otro código estaríamos obteniendo una vista con los datos de los futbolistas que
contienen tarjetas amarillas usando la sentencia INNER JOIN.
Ventajas:
Desventajas:
Rendimiento ya que las vistas crean una apariencia de tabla por lo que el
SMBD debe traducir las consultas definidas en una vista.
restricciones de actualización, cuando se solicita la actualización de una
fila de la vista se debe traducir en una petición de actualización a la tabla
de origen de la vista, esto en vistas muy grandes puede causar problemas
y evitar que las actualizaciones se realicen.
43
UNIDAD III PROCEDIMIENTOS ALMACENADOS, INDICES Y
CURSORES
SINTAXIS:
parameter:
[ IN | OUT | INOUT ] param_name type
type:
Any valid MySQL data type
45
characteristic:
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
routine_body:
procedimientos almacenados o comandos SQL válidos
Estos comandos crean una rutina almacenada. Desde MySQL 5.0.3, para crear una
rutina, es necesario tener el permiso CREATE ROUTINE , y los permisos ALTER
ROUTINE y EXECUTE se asignan automáticamente a su creador. Si se permite logueo
binario necesita también el permiso SUPER.
Por defecto, la rutina se asocia con la base de datos actual. Para asociar la rutina
explícitamente con una base de datos, especifique el nombre
como db_name.sp_name al crearlo.
Si el nombre de rutina es el mismo que el nombre de una función de SQL, necesita usar
un espacio entre el nombre y el siguiente paréntesis al definir la rutina, o hay un error de
sintaxis. Esto también es cierto cuando invoca la rutina posteriormente.
Para replicación, use la función NOW() (o su sinónimo) o RAND() no hace una rutina no
determinista necesariamente. Para NOW(), el log binario incluye el tiempo y hora y
replica correctamente. RAND()también replica correctamente mientras se invoque sólo
una vez dentro de una rutina. (Puede considerar el tiempo y hora de ejecución de la
rutina y una semilla de número aleatorio como entradas implícitas que son idénticas en
el maestro y el esclavo.)
La característica SQL SECURITY puede usarse para especificar si la rutina debe ser
ejecutada usando los permisos del usuario que crea la rutina o el usuario que la invoca.
El valor por defecto es DEFINER. Esta característica es nueva en SQL:2003. El creador
o el invocador deben tener permisos para acceder a la base de datos con la que la rutina
47
está asociada. Desde MySQL 5.0.3, es necesario tener el permiso EXECUTE para ser
capaz de ejecutar la rutina. El usuario que debe tener este permiso es el definidor o el
invocador, en función de cómo la característica SQL SECURITY .
MySQL almacena la variable de sistema sql_mode que está en efecto cuando se crea
la rutina, y siempre ejecuta la rutina con esta inicialización.
Los comandos que retornan un conjunto de resultados no pueden usarse desde una
función almacenada. Esto incluye comandos SELECT que no usan INTO para tratar
valores de columnas en variables, comandos SHOW y otros comandos como EXPLAIN.
Para comandos que pueden determinarse al definir la función para que retornen un
conjunto de resultados, aparece un mensaje de error Not allowed to return a result set
from a function (ER_SP_NO_RETSET_IN_FUNC). Para comandos que puede
determinarse sólo en tiempo de ejecución si retornan un conjunto de resultados, aparece
el error PROCEDURE %s can't return a result set in the given
context(ER_SP_BADSELECT).
mysql> delimiter ;
Al usar el comando delimiter, debe evitar el uso de la antibarra ('\') ya que es el carácter
de escape de MySQL.
El siguiente es un ejemplo de función que toma un parámetro, realiza una operación con
una función SQL, y retorna el resultado:
mysql> delimiter //
mysql> delimiter ;
49
mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world! |
+----------------+
1 row in set (0.00 sec)
Imagina que tiene toda la información telefónica de los habitantes de un país como
Venezuela, de una población aproximada de 30 millones de habitantes. Suponga
también que los datos no están ordenados.
Nota: Para que los índices se noten realmente, debemos contar con un número
significativo de registros en una tabla. Pero no es necesario que sean millones. Creando
una buena estrategia de índices podemos mejorar sensiblemente la velocidad de las
consultas en tablas con varios miles de registros. Claro está que la mejora suele ser
proporcional y depende mucho de esa cantidad de registros. También un uso
inadecuado de ellos puede redundar en pérdida de rendimiento, por lo que conviene
saber qué es lo que estamos haciendo.
Sin ningún orden en nuestros datos, MySQL debe leer todos los registros de la tabla
"personas" y efectuar una comparación entre el campo "apellido" y la cadena de
caracteres "Zamora” para encontrar alguna coincidencia (en la vida real habrá muchas
coincidencias). A medida que esta base de datos sufra modificaciones, como un
incremento en el número de registros, dicha consulta irá requiriendo un mayor el
esfuerzo de la CPU y el uso de memoria necesaria para ejecutarse.
Si abrimos un libro técnico observamos que posee un índice al final del libro, contenido
por términos o conceptos importantes con su correspondiente numero de página. Si
sabemos de qué trata el libro buscamos la palabra que nos interesa y encontramos la
expresión junto con su número de página.
Los índices de base de datos son muy similares. Al igual que el escritor decide crear un
índice de términos y conceptos importantes de su libro, como administradores de una
base de datos decidimos crear un índice respecto a una columna.
Usando el ejemplo inicial, para que la consulta anterior se ejecutase más rápido en
nuestro sistema gestor de base de datos, nos vendría bien crear un índice por apellido.
Para crear ese índice podemos utilizar una sentencia en lenguaje SQL como la siguiente:
De esta forma sencilla indicamos a MySQL que genere una lista ordenada de todos los
apellidos de la tabla personas, así como en el ejemplo del libro tenemos los números de
teléfono ordenados por el apellido.
51
(Fernández, 2013) Aunque es recomendable no abusar de los bucles en MySQL, es más,
a veces no son necesarios, y siempre hay que buscar una solución que no los use, a
veces no la vamos a encontrar y será en esos casos cuando debamos utilizarlos.
Veamos un bucle muy sencillo, parecido a un for de los de toda la vida, en el que
contamos del 1 al 9:
DELIMITER $$
CREATE PROCEDURE simple_loop ( )
BEGIN
DECLARE counter BIGINT DEFAULT 0;
my_loop: LOOP
SET counter=counter+1;
IF counter=10 THEN
LEAVE my_loop;
END IF;
SELECT counter;
cuando hagamos:
CALL simple_loop();
+———+
| counter |
+———+
| 1 |
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 2 |
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 3 |
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 4 |
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 5 |
+———+
1 row in set (0.01 sec)+———+
| counter |
+———+
| 6 |
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 7 |
53
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 8 |
+———+
1 row in set (0.01 sec)
+———+
| counter |
+———+
| 9 |
+———+
1 row in set (0.01 sec)
Vemos que el código que iteraremos está entre LOOP…END LOOP, lo que aparece
justo antes (my_loop) es una etiqueta para nombrar ese bucle. Ahora bien, en este
ejemplo simplemente incrementamos la variable counter, y con una condición IF
hacemos que el bucle llegue a su fin cuando counter sea 10. Ese 10 no lo veremos
porque abandonamos el bucle antes del SELECT.
Lo primero que vamos a hacer, será un procedimiento que incluya el bucle básico, con
SELECTs, para ver que todo funciona y que lo estamos haciendo bien. (Debajo explicaré
para qué es cada cosa):
-- Condición de salida
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin=1;
55
OPEN runners_cursor;
get_runners: LOOP
FETCH runners_cursor INTO v_name, v_time, v_penalty1, v_penalty2;
IF fin = 1 THEN
LEAVE get_runners;
END IF;
CLOSE runners_cursor;
END$$
DELIMITER ;
Dentro del bucle, analizaremos el valor de la variable fin para ver si finalizamos (LEAVE
xxxxx) o ejecutamos una iteración.
Demos un paso más, vamos a crear una función que asigne las puntuaciones a cada
uno de los corredores con una fórmula. Por ejemplo la siguiente: siendo Time el tiempo
en segundos que se tarda en realizar la prueba, 500-Time serán los puntos iniciales, a
los que tenemos que restar 5*penalty1 y 3*penalty2. Por tanto:
RETURN points;
END$$
DELIMITER ;
Ahora el código para calcular los puntos de los jugadores puede ser:
-- Condición de salida
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin=1;
OPEN runners_cursor;
get_runners: LOOP
57
FETCH runners_cursor INTO v_runner_id, v_name, v_time, v_penalty1,
v_penalty2;
IF fin = 1 THEN
LEAVE get_runners;
END IF;
CLOSE runners_cursor;
END$$
DELIMITER ;
Pero claro, como dije al principio, tenemos que mirar siempre, si hay alguna solución
posible que no utilice bucles, sobre todo porque cuando empezamos a utilizarlos nos
emocionamos (igual que dice que también nos emocionamos con las expresiones
regulares) y vemos la solución con bucles más inmediata que sin bucles, pero claro, con
bucles todo irá mucho más lento. Podríamos haber hecho:
Aunque podemos hacer algunas cosas más con el ejemplo del bucle, por ejemplo, si el
tiempo es mayor de 250, se intercambien los penalties, editando directamente el código
del bucle, metiendo una sentencia IF, aunque eso mismo lo podemos hacer también
desde la función que calcula los puntos.
Otro pequeño ejemplo (bueno, no tan pequeño) que me viene a la cabeza es que
tenemos un sistema de usuarios en el que cada usuario tiene información en tres tablas:
una para login, password e información de acceso; otra para información de perfil y otra
de permisos. En este caso, en todas las tablas excepto en la de permisos habrá una
entrada por usuario, pero en los permisos estableceremos el elemento sobre el que un
usuario tiene permiso y qué tipo de permiso tiene, y como podemos tener permiso sobre
varios objetos, puede haber varias entradas por usuario.
También tenemos una tabla de mensajes entre usuarios.
Por otro lado tenemos las páginas, que serán objetos de nuestro sistema y serán sobre
las que los usuarios podrán ver, editar, crear derivados y borrar (los diferentes permisos
del sistema), eso sí, para las páginas existe una jerarquía, por lo que podremos tener
páginas “hijas”. Pero cuando creamos una página en el sistema:
Al menos tendrán que tener permiso total sobre ella los administradores del
sistema (marcados en la tabla de acceso)
Si un usuario tenía permiso de edición sobre una página padre, podrá editar la
nueva página hija
Si un usuario podía crear derivadas en la página padre, podrá hacerlo en la hija
Si un usuario podía editar y crear derivadas en la padre, podrá borrar en la hija
Además, tenemos que enviar un mensaje (meter el mensaje en la tabla), al
usuario con los permisos que tendrá en la nueva página
Tenemos para ello las funciones y procedimientos:
o puede_crear_derivadas(usuario, pagina) – Que devolverá TRUE si el
usuario puede crear páginas derivadas
o puede_editar(usuario, pagina) – Que hará lo mismo que la anterior pero
con el nuevo permiso
o nuevo_permiso(usuario, pagina, permiso) – Insertará un nuevo permiso
en la tabla de permisos
o mensaje(from, to, mensaje) – Enviará un usuario a un usuario.
59
DECLARE v_object_id BIGINT;
DECLARE v_mens TEXT;
-- Condición de salida
DECLARE CONTINUE HANDLER FOR NOT FOUND SET fin=1;
OPEN users_cursor;
get_users: LOOP
FETCH users_cursor INTO v_user_id;
IF fin = 1 THEN
LEAVE get_users;
END IF;
CLOSE users_cursor;
END$$
DELIMITER ;
61
UNIDAD IV TRANSACCIONES, CONCURRENCIAS Y SEGURIDAD
DE BASE DE DATOS
(uaeh, 2010) El servidor de bases de datos MySQL soporta distintos tipos de tablas,
Las tablas del tipo InnoDB están estructuradas de forma distinta que MyISAM,
ya que se almacenan en un sólo archivo en lugar de tres, y sus principales
características son que permite trabajar con transacciones, y definir reglas de
integridad referencial.
Para este fin, las tablas que soportan transacciones, como es el caso de
InnoDB, son mucho más seguras y fáciles de recuperar si se produce algún
fallo en el servidor, ya que las consultas se ejecutan o no en su totalidad. Por
otra parte, las transacciones pueden hacer que las consultas tarden más tiempo
en ejecutarse.
Para asegurarnos que tenemos soporte para el tipo de tablas InnoDB podemos
ejecutar la siguiente sentencia:
+---------------------------------+------------+
| Variable_name | Value |
+---------------------------------+------------+
| have_innodb | YES |
| innodb_additional_mem_pool_size | 1048576 |
| innodb_buffer_pool_size | 8388608 |
| innodb_data_file_path | ibdata:30M |
| innodb_data_home_dir | |
| innodb_file_io_threads |4 |
| innodb_force_recovery |0 |
| innodb_thread_concurrency |8 |
| innodb_flush_log_at_trx_commit | 1 |
| innodb_fast_shutdown | ON |
| innodb_flush_method | |
| innodb_lock_wait_timeout | 50 |
| innodb_log_arch_dir |. |
| innodb_log_archive | OFF |
| innodb_log_buffer_size | 1048576 |
| innodb_log_file_size | 5242880 |
63
| innodb_log_files_in_group |2 |
| innodb_log_group_home_dir |. |
| innodb_mirrored_log_groups |1 |
| innodb_max_dirty_pages_pct | 90 |
+---------------------------------+------------+
En efecto, una de las principales características de las tablas del tipo InnoDB es
que pueden trabajar con transacciones, o sentencias SQL que son agrupadas
como una sola. Un ejemplo típico de esto es una transacción bancaria. Por
ejemplo, si una cantidad de dinero es transferida de la cuenta de una persona a
otra, se requerirán por lo menos dos consultas:
Estas dos consultas deben trabajar bien, ¿pero que sucede si ocurre algún
imprevisto y "se cae" el sistema después de que se ejecuta la primer consulta,
pero la segunda aún no se ha completado?. La persona1 tendrá una cantidad
de dinero removida de su cuenta, y creerá que ha realizado su pago, sin
embargo, la persona2 estará enfadada puesto que pensará que no se le ha
depositado el dinero que le deben. En este ejemplo tan sencillo se ilustra la
necesidad de que las consultas sean ejecutadas de manera conjunta, o en su
caso, que no se ejecute ninguna de ellas. Es aquí donde las transacciones
toman un papel muy importante.
Vamos a ejecutar algunas consultas para ver como trabajan las transacciones.
Lo primero que tenemos que hacer es crear una tabla del tipo InnoDB e insertar
algunos datos.
Para crear una tabla InnoDB, procedemos con el código SQL estándar
CREATE TABLE, pero debemos especificar que se trata de una tabla del tipo
InnoDB (TYPE= InnoDB). Esto es aplicable a cualquier tipo de tabla, pero
cuando no se especifica nada, MySQL supone que se trata de una tabla
MyISAM.
mysql> CREATE TABLE innotest (campo INT NOT NULL PRIMARY KEY) TYP
E = InnoDB;
65
mysql> SELECT * FROM innotest;
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
+-------+
mysql> BEGIN;
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
| 4|
+-------+
mysql> ROLLBACK;
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
+-------+
mysql> BEGIN;
67
mysql> SELECT * FROM innotest;
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
| 4|
+-------+
mysql> EXIT;
Bye
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
+-------+
mysql> BEGIN;
mysql> COMMIT;
mysql> EXIT;
Bye
69
Your MySQL connection id is 450 to server version: 4.0.13
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
| 4|
+-------+
Por default, las tablas InnoDB ejecutan una lectura consistente (consistent read).
Esto significa que cuando una sentencia SELECT es ejecutada, MySQL regresa
los valores presentes en la base de datos hasta la transacción más reciente que
ha sido completada. Si alguna transacción está en progreso, los cambios hechos
por alguna sentencia INSERT o UPDATE no serán reflejados. Sin embargo,
existe una excepción: las transacciones abiertas si pueden ver sus propios
cambios. Para demostrar esto, necesitamos establecer dos conexiones al
servidor MySQL.
Primero agregaremos un registro dentro de una transacción con la primera
conexión (ID 524):
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
Ahora, desde la segunda conexión (ID 525) consultamos los datos de nuestra
tabla.
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
Como se puede observar, el registro que hemos insertado desde la 1ra. conexión
no es regresado puesto que forma parte de una transacción que no ha sido
completada. Ahora, desde la 1ra. conexión ejecutamos la misma consulta
SELECT.
71
mysql> SELECT * FROM innotest;
+-------+
| campo |
+-------+
| 1|
| 2|
| 3|
| 4|
| 5|
+-------+
5 rows in set (0.00 sec)
Vamos a crear una sencilla tabla llamada ventas que sea del tipo InnoDB.
Insertamos un registro.
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
Actualizamos el registro.
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.05 sec)
4.4. Transacciones
Una transacción es una unidad de programa que accesa y posiblemente actualiza varios
elementos de datos.
Estados de transacción
Programación
Crear Conexión
Abrir Conexión
(Openconnection)
Iniciar Transacción
(Begin Transaction) setAutoCommit(0/false)
Queries...
(Insert, Select, Update, Delete...)
-Error
(Abort Transaction) rollback
75
Procesar resultados
(Print, a= , b= )
Asegurar Transacción
(End Transaction) commit
Cerrar Conexión
(Closeconnection)
Notas:
Es importante recordar que muchos de los datos de la base no se encuentran nada más
en disco, sino tambien en los buffers de memoria, de ahí que el scheduler interactúa con
ellos y en su defecto solicita la lectura de los datos del disco.
Ilustración 1: concurrencias
El calendarizador crea agendas, secuencias ordenadas de las acciones tomadas por una
o más transacciones.
77
SET AUTOCOMMIT = {0 | 1}
dirty read: Una transacción lee datos escritos por una transacción concurrente
que no ha hecho "commit"
nonrepeatable read: Una transacción re-lee datos que leyó previamente y
encuentra que han sido modificados por otra transacción (que hizo commit en el
inter).
phantom read: Una transacción re-ejecuta un query regresando un conjunto de
tuplas que satisfacen una condición de búsqueda y encuentra que el resultado
ha cambiado debido a otra transacción que hizo "commit" recientemente.
T1 T2
mysql> set autocommit=0; mysql> set autocommit=0;
Query OK, 0 rows affected (0.09 sec) Query OK, 0 rows affected
mysql> select * from bank; (0.00 sec)
+------+-------+ mysql> select * from bank;
| id | debit | +------+-------+
+------+-------+ | id | debit |
| 32 | 999 | +------+-------+
| 64 | 7865 | | 32 | 999 |
+------+-------+ | 64 | 7865 |
2 rows in set (0.00 sec) +------+-------+
mysql> insert into bank values(66,3453); 2 rows in set (0.00 sec)
Query OK, 1 row affected (0.09
sec)
79
| 66 | 3453 |
+------+-------+
3 rows in set (0.00 sec)
mysql> delete from bank where id=64;
Query OK, 1 row affected (0.12
sec)
mysql> select * from bank; mysql> select * from bank;
+------+-------+ +------+-------+
| id | debit | | id | debit |
+------+-------+ +------+-------+
| 32 | 999 | | 32 | 999 |
| 66 | 3453 | | 64 | 7865 |
+------+-------+ +------+-------+
2 rows in set (0.00 sec) 2 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00
mysql> commit; sec)
Query OK, 0 rows affected (0.07 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00
sec)
mysql> set autocommit=0; mysql> select * from bank;
Query OK, 0 rows affected (0.00 sec) +------+-------+
mysql> select * from bank; | id | debit |
+------+-------+ +------+-------+
| id | debit | | 32 | 999 |
+------+-------+ | 66 | 3453 |
| 32 | 999 | +------+-------+
| 66 | 3453 | 2 rows in set (0.00 sec)
+------+-------+ mysql> rollback;
2 rows in set (0.00 sec) Query OK, 0 rows affected
mysql> rollback; (0.01 sec)
Query OK, 0 rows affected
(0.00 sec)
mysql> set autocommit=0; mysql> set autocommit=0;
Query OK, 0 rows affected Query OK, 0 rows affected
(0.01 sec) (0.00 sec)
mysql> select * from bank where id=32 mysql> update bank set debit=666
for update; where id=32;
+------+-------+ .
| id | debit | .
+------+-------+ .
| 32 | 999 | .
+------+-------+ .
1 row in set (0.00 sec) .
mysql> rollback; .Wait unlock
Query OK, 0 rows affected .
(0.00 sec) .
.
.
mysql> update bank set debit=666
where id=32;
Query OK, 1 row affected
(13.02 sec)
Rows matched: 1
mysql> select * from bank; Changed: 1 Warnings: 0
+------+-------+
| id | debit | mysql> select * from bank;
+------+-------+ +------+-------+
| 32 | 999 | | id | debit |
| 66 | 3453 | +------+-------+
+------+-------+ | 32 | 666 |
2 rows in set (0.00 sec) | 66 | 3453 |
+------+-------+
2 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected
(0.07 sec)
81
+------+-------+ +------+-------+
| id | debit | | id | debit |
+------+-------+ +------+-------+
| 32 | 999 | | 32 | 666 |
| 66 | 3453 | | 66 | 3453 |
+------+-------+ +------+-------+
2 rows in set (0.00 sec) 2 rows in set (0.01 sec)
mysql> commit;
Query OK, 0 rows affected
(0.07 sec)
mysql> select * from bank; mysql> select * from bank;
+------+-------+ +------+-------+
| id | debit | | id | debit |
+------+-------+ +------+-------+
| 32 | 666 | | 32 | 666 |
| 66 | 3453 | | 66 | 3453 |
+------+-------+ +------+-------+
2 rows in set (0.01 sec) 2 rows in set (0.01 sec)
83
+------+-------+
2 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected
(0.00 sec)
mysql> select * from bank;
+------+-------+
| id | debit |
+------+-------+
| 32 | 777 |
| 66 | 3453 |
+------+-------+
2 rows in set (0.01 sec)
85
mysql> update bank set debit=000 where | id | debit |
id=32; +------+-------+
Query OK, 1 row affected (6.88 | 32 | 111 |
sec) | 66 | 3453 |
Rows matched: 1 Changed: 1 +------+-------+
Warnings: 0 2 rows in set (0.00 sec)
mysql> select * from bank;
+------+-------+
| id | debit |
+------+-------+
| 32 | 0 |
| 66 | 3453 |
+------+-------+
2 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected
(0.00 sec)
87
Query OK, 0 rows affected
(0.00 sec)
mysql> select * from bank;
+------+-------+
| id | debit |
+------+-------+ mysql> select * from bank;
| 32 | 333 | +------+-------+
| 66 | 3453 | | id | debit |
+------+-------+ +------+-------+
2 rows in set (0.00 sec) | 32 | 0 |
| 66 | 3453 |
+------+-------+
2 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected
(0.00 sec)
mysql> select * from bank;
+------+-------+
| id | debit |
+------+-------+
| 32 | 333 |
| 66 | 3453 |
+------+-------+
2 rows in set (0.00 sec)
mysql> set autocommit=0; mysql> set autocommit=0;
Query OK, 0 rows affected Query OK, 0 rows affected
(0.00 sec) (0.00 sec)
mysql> select * from bank where
id=32 lock in share mode;
+------+-------+
| id | debit |
+------+-------+
| 32 | 333 |
+------+-------+
1 row in set (0.00 sec)
89
>al hacer el update en T2 ahora T2
mysql> update bank set debit=444 where espera a T1
id=32; >por lo tanto se produce un
Query OK, 1 row affected deadlock
(30.83 sec) >el dbms hace rollback en T2
Rows matched: 1 Changed: 1 (ultimo en espera) y procesa T1
Warnings: 0
91
| 66 | 3453 | +----+-------+
+----+-------+ | id | debit |
2 rows in set (0.01 sec) +----+-------+
| 32 | 555 |
| 66 | 3453 |
+----+-------+
2 rows in set (0.00 sec)
En los SGBD en general pueden intervenir una gran cantidad de usuarios, cada uno con
mayor o menor nivel de acceso y cualificación. Respecto a la seguridad de una base de
datos, conviene recordar qué tipo de usuarios se distinguen:
Administrador
Usuario técnico
Son aquellos que elaboran aplicaciones del SGDB para ser utilizadas por los usuarios
finales.
Usuario final
Usuarios no especializados. Utilizan las aplicaciones diseñadas por los técnicos para
manejar la base de datos. La información que tratan está restringida al marco de su
actividad concreta por medio de los subesquemas (vistas) previamente definidos.
Permisos
La segunda etapa del control de acceso consiste en una serie de operaciones que
realiza el servidor para verificar que cada cliente tiene suficientes privilegios para realizar
sus peticiones. En este proceso, se accede a las tablas:
Los valores en estas tablas son tipo "sí" (Y) y "no" (N). Un permiso Y, autoriza a realizar
la operación. Un permiso N, hará al sistema pasar a la siguiente tabla (desde db hasta
todas las tables_priv y columns_priv) hasta dar con permisos positivos. Si ninguna tabla
autoriza al usuario (todas con valor N), la operación será denegada.
93
Columnas de alcance: Determinan el alcance de cada registro en las tablas, es
decir, el contexto en que el registro se aplica.
Columnas de privilegios: Indican qué privilegios se otorgan a una cuenta sobre
ciertas bases de datos, tablas y/o columnas (y otros objetos del SGBD).
Al realizar una nueva conexión, el servidor realiza comprobaciones sobre las tablas de
permisos:
4.10. Aplicación
Para concluir con el contenido de la guía, el estudiante deberá elaborar una aplicación
que sirva para la administración de base de datos, la misma que podrá realizarla con el
uso de cualquier lenguaje de programación.
Bibliografía
Amor, R. V. (11 de Septiembre de 2015). Adictos al trabajo. Obtenido de Introducción a índices
en MySQL: https://www.adictosaltrabajo.com/2015/09/11/introduccion-a-indices-en-
mysql/
Barrena, A. (24 de 09 de 2015). anerbarrena.com. Obtenido de Crear una tabla en una base de
datos: https://www.anerbarrena.com/create-table-mysql-5023/
Barrena, A. (11 de 01 de 2016). ANER BARRENA. Obtenido de CREAR VISTAS:
https://www.anerbarrena.com/create-view-mysql-5101/
Fernández, G. (6 de diciembre de 2013). poesiabinaria.net. Obtenido de
https://poesiabinaria.net/2013/12/bucles-y-cursores-en-mysql-con-ejemplos/:
https://poesiabinaria.net/2013/12/bucles-y-cursores-en-mysql-con-ejemplos/
Gardey, J. P. (22 de 11 de 2012). Definicion.de. Obtenido de Definición de modelo de datos:
https://definicion.de/modelo-de-datos/
GUEBS. (12 de 05 de 2016). MANUALES. Obtenido de DISPARADORES:
https://manuales.guebs.com/mysql-5.0/triggers.html
Hispano, M. (25 de 07 de 2016). Transacciones en Mysql. Obtenido de Programacion.net:
https://programacion.net/articulo/transacciones_en_mysql_242
Jairo, J. (15 de 04 de 2012). Mysql. Obtenido de funciones de agrupamiento:
http://jjmojicamysql.blogspot.com/2012/04/34-funciones-de-agrupamiento-count-
max.html
Java, E. (13 de 11 de 2010). Edu Java. Obtenido de DL y DML. Sentencias SELECT FROM
WHERE y ORDER BY con Mysql Workbench.: http://www.edu4java.com/es/sql/sql4.html
Logicalis. (12 de 07 de 2015). Modelo relacional en la gestión de bases de datos. Obtenido de
Modelo relacional en la gestión de bases de datos:
https://blog.es.logicalis.com/analytics/conceptos-basicos-del-modelo-relacional-en-la-
gestion-de-bases-de-datos
Lucid. (10 de 09 de 2015). Lucid Chart. Obtenido de Qué es un modelo de base de datos:
https://www.lucidchart.com/pages/es/qu%C3%A9-es-un-modelo-de-base-de-datos
MirCha, J. (22 de 10 de 2014). EDTEAM. Obtenido de Modelo Entidad-Relación:
https://ed.team/blog/modelo-entidad-relacion
Morales, J. D. (30 de 06 de 2014). IBM. Obtenido de Características y tipos de bases de datos:
https://www.ibm.com/developerworks/ssa/data/library/tipos_bases_de_datos/index.html
MUÑOZ, E. (29 de 01 de 2015). A un clic de distancia. Obtenido de A un clic de distancia:
https://aunclicdedistancia.wordpress.com/2015/01/29/pasar-del-modelo-entidad-
relacion-al-modelo-relacional/
uaeh. (10 de 09 de 2010). cidecame. Obtenido de lenguaje de manipulacion de datos:
http://cidecame.uaeh.edu.mx/lcc/mapa/PROYECTO/libro14/53__lenguaje_de_manipula
cin_de_datos_dml.html
95
Valencia, U. P. (04 de 01 de 2011). Blog Historia de la Informática. Obtenido de Historia de las
bases de datos: http://histinf.blogs.upv.es/2011/01/04/historia-de-las-bases-de-datos/