Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Versión 1.1
Óscar Gómez
Curso 2012-2013
Índice general
1. Introducción 3
1.1. Historia de las bases de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2. Historia del software libre GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3. Un repaso al resto del libro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3. Diseño físico 27
3.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2. BBDD en Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.3. Claves ajenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.4. MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.5. Tablespaces y undo files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4. Consultas SQL 39
4.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.2. La sentencia SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.3. Condiciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.4. Consultas con agregados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.5. Consultas multitabla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.6. Algunos ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.7. Subconsultas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.8. Actualización y borrado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
5. Programación 61
5.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.2. Procedimientos almacenados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.3. Sentencias básicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
I
5.4. Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.5. Funciones MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.6. Solución al examen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
6. Administración 79
6.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
6.2. Aspectos básicos de las contraseñas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
6.3. El sistema de privilegios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
6.4. El sistema de concesiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.5. Usuarios con restricciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.6. Vistas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
6.7. Recuperando la clave de root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6.8. Copias de seguridad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
7. Access 89
7.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
7.2. El entorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
II
Bases de datos, Versión 1.1
Contents:
Índice general 1
Bases de datos, Versión 1.1
2 Índice general
CAPÍTULO 1
Introducción
3
Bases de datos, Versión 1.1
4 Capítulo 1. Introducción
CAPÍTULO 2
2.1 Introducción
En general, la construcción de una casa se considera un proyecto de envergadura. Dado que no se puede
permitir que cada uno de los participantes en el proyecto siga su propio ritmo o haga lo que crea con-
veniente, se asume que habrá un arquitecto que diseña una estructura y realiza los cálculos necesarios
para que todo se construya correctamente. En las bases de datos ocurre lo mismo: determinados nego-
cios necesitarán una infraestructura de información muy sofisticada por lo que puede ser conveniente
disponer de unos “planos” que permitan la comunicación entre los distintos miembros que participan en
un proyecto de desarrollo de un programa informático.
Además, muy a menudo ocurre que transcurrido un tiempo, el usuario del programa desea hacer mejoras
o ampliaciones pero por desgracia, la estructura de una base de datos o de un programa no son tan visibles
como los muros de una casa. La existencia de los planos o diagramas que expliquen como se hizo una
base de datos pueden ser de gran ayuda para tales mejoras. Es de esperar que un cliente con visión de
futuro exija una cierta documentación de como se hizo un programa.
Por otro lado, un problema habitual para los desarrolladores informáticos es la necesidad de conocer un
poco el “dominio de conocimiento”. Es decir, si se necesita construir una base de datos que almacene
información sobre impuestos, es muy probable que primero se necesite conocer un poco más como
funciona ese mundo. El conocimiento que se obtenga junto a los requisitos que tenga el cliente deberían
plasmarse de alguna forma en un documento.
Al igual que la construcción de una casa requiere la elaboración de planos y cálculos el diseño de una
estructura de almacenamiento de datos requiere que exista un mecanism
Los diagramas como “planos” de una BBDD. Se utilizarán para que despues todo el mundo pueda
entender qué hay dentro de la BBDD por si se necesita modificar algo.
Un problema fundamental es el dominio de conocimiento. Como informáticos debemos intentar
adquirir el conocimiento del cliente para reflejarlo en una BD. En esencia debemos intentar extraer
la información RELEVANTE
Otro problema de gran importancia es la ambigüedad. Se debe concretar al máximo el significado
de cada palabra o término específico.
En suma, un informático va a construir un modelo del conocimiento del cliente. La primera labor
a la hora de construir una BD es modelar la información.
5
Bases de datos, Versión 1.1
El modelo E/R se remonta al año 1970, cuando Peter Chen observó lo complejo que era diseñar una base
de datos. Decidió crear un lenguaje común de símbolos que facilitara la comunicación.
2.3.1 Entidades
Se denomina entidad a cualquier elemento sobre el cual se desea almacenar información. Aunque las
entidades suelen corresponderse con los sustantivos, no todos los sustantivos merecen ser entidades que
aparezcan en el modelo.
Las entidades pueden ser fuertes o débiles:
Una entidad fuerte es aquella que existe por sí sola.
Una entidad débil es aquella que requiere que otra entidad exista antes que ella.
Supongamos una situación como “empleado realiza viajes”. No se puede almacenar nada sobre un viaje
si previamente no existe un empleado que lo realice.
En la debilidad hay dos posibilidades:
Dependencia en existencia: una entidad es débil con dependencia en existencia si antes de poder
“existir” o “almacenarse” requiere que otra entidad exista primero.
Dependencia en identificación: la entidad débil no tiene clave propia sino que necesita la de otra
entidad.
En general una misma entidad puede ocurrir muchas veces, se dice que una entidad puede tener “varias
instancias”. Una entidad “Coche” puede tener infinitas instancias como “Seat Ibiza CR-2785-X”, “Re-
nault 21 8765-CWG”, ...
2.3.3 Interrelaciones
Son asociaciones entre entidades. En general se corresponden con los verbos. Se representan por medio
de un rombo con el nombre dentro.
Las interrelaciones pueden ser entre distintos conjuntos de entidades
Interrelación binaria: se da entre dos entidades.
Interrelación ternaria: se da entre tres entidades que participan de forma simultánea en una aso-
ciación.
Interrelación n-aria.
Interrelaciones reflexivas: se dan entre una entidad y sí misma. El principal ejemplo se da en la
sentencia “unos empleados son jefes de otros”.
En las bases de datos se debe reflejar el hecho de que las entidades puedan aparecer 0 veces, 1 vez,
muchas veces.
En el diagrama, se ponen las cardinalidades junto a la entidad y con el mínimo y el máximo.
Para abreviar,a veces se ponen los máximos encima de la relación y tendremos entonces relaciones como
esta:
“Uno a uno” o 1:1
“Uno a muchos” o 1:n
“Muchos a muchos” o m:n
Ejercicios: hacer el diagrama E/R con entidades, debilidades, interrelaciones y cardinalidades de los
siguientes supuestos.
Hombre se casa con mujer en sociedad monógama
Hombre se casa con mujer en sociedad polígama masculina
Hombre se casa con mujer en sociedad polígama mixta
Pescador pesca pez
Arquitecto diseña casa
2.3.5 Atributos
Se denomina atributos a propiedades de las entidades que tienen la importancia suficiente para almacenar
datos sobre ellas y que por tanto aparecerán en el diagrama E/R.
Los atributos suelen tener un dominio: es decir un conjunto de valores del cual toman su información.
Un detalle sutil pero importante es que en ocasiones los atributos no son de las entidades, sino de las
relaciones. Ej: pensemos en el diseño E/R de un enunciado como este: “un mecanico repara un coche en
una cierta fecha del año”. La información de un conjunto cualquiera de mecánicos podría ser la siguiente
Ya hemos dicho que hay entidades que muestran “debilidad” en base a dos características
Dependencia en existencia: por ejemplo la entidad “Transacción” es débil con respecto a “Cuenta
Corriente”. En este caso, la interrelación llevará una letra E, para indicar este tipo de dependencia.
Dependencia de identificación: en este caso, la relación utiliza una I para señalar la dependencia.
Ejercicio:¿Qué tipo de relación existe entre estas entidades?
1. Toro y Ganadería: Toro es débil (dependencia en identificación) con respecto a Ganadería.
2. Una empresa tiene un párking y desea almacenar qué empleados aparcan vehículos y los datos
sobre los mismos.
Enunciado
Analiza el siguiente enunciado y transfórmalo en DOS diagramas E/R. ¿Qué características reflejan uno
u otro modelo?:
Una serie de empresas con CIF, Nombre y Dirección desean ofrecer beneficios a sus clientes. Estos
beneficios tienen un código, una descripción y una limitación. Para obtener dichos beneficios se emiten
una serie de cupones que tienen un código y una fecha de vencimiento
Solución
No hay una solución correcta a partir de lo que nos dicen. Podemos pensar en dos posible situaciones
1. Las empresas son libres de ofrecer beneficios, modificarlos y hacer cambios cuando lo deseen.
2. Los beneficios solo los inserta un administrador y las empresas deben ceñirse a la lista de posibil-
idades que les ofrecemos
Esto da lugar a que el ejemplo a) sea un modelo en el que se da libertad mientras que el modelo b) sea
más rígido, lo que a su vez condiciona el modelo
Podemos por tanto contemplar dos soluciones a partir de las tres entidades Empresa, Beneficio y Cupón
1. Dos relaciones binarias
Relación “Empresa ofrece Beneficio”
Relación “Beneficio Se Plasma En Cupón”
2. Una sola relación ternaria “Empresa con Beneficio con Cupón”
Imaginemos las tres tablas, Empresa, Beneficio y Cupón.
CIF Nombre Direccion
E1 ACME C/ Guadiana
E2 XYZ Sport C/ Rio
2.3.8 Herencia
En ocasiones hay objetos que comparten muchas propiedades y características. Supongamos el ejemplo
de una base de datos para la DGT. Para cada coche puede haber un dueño, pero este dueño puede
ser una persona física o jurídica. Si construyéramos dos entidades separadas “Persona” y “Empresa”
descubriríamos que tienen cosas en común.
Para ahorrar esfuerzos se puede poner una sola entidad general que “ofrece” los atributos, y dichos
atributos son “heredados” por las entidades hija.
Cuando hay una herencia es posible que una instancia pueda ser de dos entidades a la vez. Por ejemplo,
pensemos en las entidades “Personal Contratado” y las entidades “Estudiante” y “Trabajador”. ¿Puede
una persona ser estudiante y trabajador a la vez? SÍ . Por lo tanto esta herencia no es disjunta, pero la de
“Persona” y “Empresa” sí es disjunta.
Las herencias disjuntas se marcan con una “d” en el triángulo.
A veces dos entidades pueden ir relacionadas por dos o más conexiones. En determinadas situaciones
interesa restringir el número de conexiones posibles.
Por ejemplo, cuando una entidad “Cliente” se conecta con una entidad “Piso” puede hacerlo por medio
de varias relaciones como “Vende”, “Alquila”, “Hace leasing”. Si por ejemplo la ley obligase a que solo
podamos tener un tipo de relación, se pondrá un arco en las relaciones.
2.4 Problemas
Una firma de abogados dedicada a la administración de fincas desea tener una base de datos para ges-
tionar la información de sus clientes.
La firma tiene varios abogados y cada uno de ellos ejerce de administrador de una o más comunidades de
vecinos, por lo que cobra unos honorarios anuales. Una comunidad es gestionada por un único admin-
istrador (nombre, DNI y número de colegiado). Las funciones de un administrador consisten en llevar la
contabilidad de la comunidad, gestionar los recibos y realizar los pagos a las distintas compañías (luz,
agua...)
De las empresas que cada comunidad tiene contratadas se guarda su nombre, dirección, teléfono y una
persona de contacto. Además puede interesar tener agrupadas a las compañías por sectores (sector de
seguridad, sector de suministros básicos).
De cada comunidad se almacena un código, su nombre, calle, código postal y población. Cada co-
munidad consta de una serie de propiedades que pueden ser de tres tipos (vivienda particular, local y
oficina). Cada propiedad se caracteriza por un número de portal, planta y letra, un nombre y apellidos
del propietario, un porcentaje de participación en los gastos de la comunidad así como los datos de la
cuenta bancaria en la que el propietario desea se le domicilie el pago de los recibos.
Si el propietario no habita en su propiedad se necesitan sus datos (nombre, apellidos, dirección y telé-
fono) y los datos de su inquilino (nombre apellidos y teléfono).
Si la vivienda es particular se guarda el número de habitaciones. Si es un local se almacena el tipo de
local y el horario. Si es una oficina se guarda la actividad a la que se dedica.
Cada comunidad tiene un presidente (nombre, apellidos y propiedad de la que son dueños) y varios
vocales que tratan con el administrador los asuntos que hay que tratar. Cada comunidad tiene una cuenta
en un banco y todo banco tiene un código y un nombre comercial. De las cuentas se almacena el código
de cuenta (que consta de un código de sucursal, dos dígitos de control y un número de cuenta) y un
saldo. Para identificar la cuenta hay que añadir el código del banco al código de cuenta.
Se almacenan dos tipos de apuntes:
2.4. Problemas 11
Bases de datos, Versión 1.1
El banco emite los recibos, pero el administrador guarda información sobre dichos recibos como
el número de recibo, fecha, importe y si se ha podido cobrar o no. Esta última información se
necesitará para llevar un registro de impagados.
En cuanto a los apuntes sobre gastos se tienen los importes que cobran las empresas contratadas
por cada comunidad. Las compañías cobran sus recibos (número, fecha e importe) cargándolo en
la cuenta de la comunidad
1.1.9. Sector
1.1.10. Tipos
1.1.10.1. Viv. particular
Num. habitaciones
1.1.10.2. Local
Tipo
Horario
1.1.10.3. Oficina
Actividad
1.1.11. Propietario
1.1.1. Nombre
1.1.2. Apellidos
1.1.3. Dirección
1.1.4. Teléfono
Al leer que un propietario tiene que aparecer como entidad, descubrimos que
“Propiedad” va a ser débil, como supusimos.
1.1.12. Inquilino
1.1.12.1. Nombre
1.1.12.2. Apellidos
1.1.13. Presidente
1.1.13.1. Nombre
1.1.13.2. Apellidos
1.1.13.3. Propiedad que poseen
1.1.14. Vocales
1.1.15. Cuenta
1.1.15.1. Código de cuenta
1.1.15.2. DC
1.1.15.3. Número de cuenta
1.1.15.4. Código de banco
Como nos dicen que se necesita el código del banco para poder
“identificar” esta entidad, hemos descubierto que esta entidad es dé-
bil
1.1.16. Banco
1.1.16.1. Codigo de banco
1.1.16.2. Nombre comercial
2.4. Problemas 13
Bases de datos, Versión 1.1
1.1.17. Apunte
1.1.17.1. Recibo (cobramos a prop)
Número de recibo
Fecha
Importe
¿Se pagó?
1.1.17.2. Pago (pagamos luz..)
Número de recibo
Importe
Fecha
1.2. Verbos: relaciones
1.2.1 “Abogado” administra “Comunidad”
1.2.2 “Abogado” cobra “Honorarios” (¡¡MAL!!, los honorarios no llegarán a ser enti-
dad)
1.2.3 “Comunidad” es gestionada por “Abogado” es lo mismo que “administra”
1.2.4 “Administrador” realiza funciones
1.2.5 “Comunidad” contrata “Empresa”
1.2.6 “Comunidad” consta de “Propiedades”
1.2.7 “Propiedad” paga a través de “Cuenta”
1.2.8 “Comunidad” tiene “Presidente”
1.2.9 “Comunidad” posee “Vocales”
1.2.10 “Comunidad” opera con “Cuenta”
1.2.11 “Banco” emite “Recibo”
La federación de ajedrez desea disponer de una base de datos de todas las partidas que se celebren bajo
su auspicio.
Toda partida viene caracterizada por una fecha de inicio, una duración en horas, los jugadores que
se enfrentaron y si eligieron blancas o negras
Dos jugadores pueden enfrentarse solo una vez por día, aunque pueden hacerlo muchas veces en
días distintos.
Se anota cada movimiento de la partida: número de movimiento, casilla de origen y casilla de
destino. Si se borra una partida se deben borrar los movimientos
Las partidas no pueden ser aplazadas
De los jugadores se recogen sus nombres, apellidos, dirección postal y electrónica, la federación
a la que pertenecen y el número de federado (que es único en cada federación)
Solo hay una federación por país con un nombre, país al que pertenece, telefono de contacto y
fecha de fundación
Una federación no se clausura hasta que no se reasignan sus jugadores a otra federación.
Las partidas pueden darse o no dentro de un torneo. Los torneos tienen un nombre, periodicidad,
fecha de creación y son organizados por una federación
En cada edición de un torneo (número ordinal) se registran todos los enfrentamientos y el nombre
del ganador. También se anotan la fecha de inicio, la cuantía del premio y el jugador que lo gana
Si desaparece una federación, desaparecen los torneos y por ende, sus ediciones
Aunque un jugador desaparezca, sus partidas no deben desaparecer
Entidades
Federación
• Atributo:nombre
• Atributo:país
Partida
• Atributo:fecha de inicio
• Atributo:duración
• Atributo:¿blancas?
Jugador
• Atributo:nombre
• Atributo:apellidos
• Atributo:dirección postal
• Atributo:dirección electrónica
• Atributo:num de federado
Movimiento
• Atributo:número
• Atributo:casilla origen
• Atributo:casilla destino
Torneo: es una entidad débil ya que nos dicen “Si desaparece una federación, desaparecen los
torneos y por ende, sus ediciones”. Por tanto, no puede haber torneo en la BD sin que haya una
federación que lo organice.
• Atributo:nombre
• Atributo:periodicidad
• Atributo:fecha
2.4. Problemas 15
Bases de datos, Versión 1.1
• Atributo:ganador
• Atributo:fecha inicio
• Atributo:periodicidad
• Atributo:cuantía del premio
Relaciones
Se necesita una relación para conectar los jugadores con partida: “Partida enfrenta jugadores”. El
enfrentamiento tiene atributos
• También podríamos considerar que hay una sola relación reflexiva “Jugador Se Enfrenta Con
Jugador”. Esta relación tendría atributos como “fecha de inicio”, “duración”, etc...
“Partida Consta De Movimiento”: aquí se descubre que Movimiento es débil, no puede almace-
narse un movimiento sin que esté “dentro de una partida”
“Jugador Pertenece A Federación”.
Hay dos posibilidades de relación
• “Federación organiza Torneo que Consta De Partidas”: relación ternaria
• “Federación organiza Torneo y Torneo Consta De Partidas”: dos binarias
• Dado que se permite que las partidas estén o no dentro de un torneo es más apropiados que
el modelo permita cierta libertad para lo cual es más apropiado utilizar las dos binarias.
El departamento de formación de una empresa desea construir una BD para planificar y gestionar la
formación de sus empleados. Los supuestos semánticos que deben recogerse son los siguientes:
La empresa organiza cursos internos de formación de los que se desea conocer el código de curso,
el nombre, una descripción, el número de horas de duración y el coste del curso.
Un curso puede tener como prerrequisito haber realizado otro(s) previamente, y, a su vez, la real-
ización de un curso puede ser prerrequisito de otros. Un curso que es prerrequisito de otro puede
serlo de forma obligatoria u opcional.
Un mismo curso tiene diferentes ediciones, es decir, se imparte en distintos lugares,fechas y con
diversos horarios (intensivo, mañana o tarde). En una misma fecha de inicio sólo puede impartirse
una edición de un curso.
Los cursos se imparten por personal de la propia empresa. Un curso puede tener varios docentes
pero una edición sólo tiene un profesor.
De los empleados se desea almacenar su código de empleado, nombre y apellidos,dirección, telé-
fono, NIF, fecha de nacimiento, nacionalidad, sexo, firma y salario,así como si está o no capacitado
para impartir cursos.
Un mismo empleado puede ser docente en una edición de un curso y alumno en otra edición, pero
nunca puede ser ambas cosas a la vez (en una misma edición de un curso o lo imparte o lo recibe)
Entidades
Curso
• Código de curso (clave)
• Nombre
• Descripción
• Duración (número de horas)
• coste
Edición (débil con respecto a curso)
• Lugar
• Fecha: clave
• Horario
Empleado
• Nombre
• Ap
• Dirección
• Tlf
• Dni: clave
• Nacionalidad
• Firma
• Sexo
• Salario
• Capacitado
Relaciones
2.4. Problemas 17
Bases de datos, Versión 1.1
Se desea diseñar una Base de Datos para gestionar los empleados y productos a la venta de una cadena
de viveros dedicados a la venta de diversos productos relacionados con la jardinería. Los supuestos que
hay que recoger en la BD son los siguientes:
La cadena de viveros dispone de varios viveros en la provincia de Madrid identificados por un
código de tienda y de los que se almacenará un teléfono, una dirección y un responsable que será
uno de los empleados que trabaja en el vivero (es necesario almacenar durante qué períodos de
tiempo ha sido responsable cada empleado).
Los productos que se venden tienen asignado un código de producto y nos interesa guardar el
precio y el stock que hay de cada producto en cada uno de los viveros y pueden ser de tres tipos:
plantas de las que se guardará su nombre, y una breve descripción de los cuidados que requiere;
accesorios de jardinería y artículos de decoración.
Estos productos se distribuyen en zonas dentro de cada vivero cada una de ellas identificadas por
un nombre dentro de cada vivero (zona exterior regadío, interior climatizada, zona de caja, etc.).
Se desea conocer el stock de cada producto de acuerdo a las zonas del vivero.Los empleados
estarán asignados a una determinada zona en un vivero la cual podrá cambiar a lo largo del tiempo
(se guardará histórico de ello) y además, los empleados puedenmo verse de un vivero a otro según
las necesidades en distintos períodos de tiempo.
De los empleados se quiere conocer su DNI, su nombre y un teléfono de contacto.En cuanto al
proceso de venta de los distintos productos, sólo se almacenarán los pedidos que realizan los
clientes pertenecientes al Club VIP que es una promoción especial que permite a los clientes
obtener descuentos según las cuantías de sus compras. De estos clientes se almacena su DNI, su
nombre, dirección, teléfono y la fecha de incorporación al club así como los datos de sus pedidos
que incluyen un número de pedido, la fecha de realización, los productos adquiridos junto con las
unidades y el descuento realizado; por último, también se incluye el precio de los portes en caso
de que se hayan contratado. De cada cliente se almacenarán todos los pedidos que haya realizado
hasta la fecha.En cuanto a estos pedidos de clientes pertenecientes al Club VIP interesa también
guardar quién fue el empleado que lo gestionó y en qué vivero se realizó el pedido teniendo en
cuenta que un pedido en un determinado vivero lo gestiona un único empleado
Entidades:
Empleado
• DNI
• Nombre
• Número de contacto
Producto
• Código
• Precio
• Stock (más tarde se descubre que stock NO ES UN ATRIBUTO DE PRODUCTO sino de
una relación)
Planta es una entidad hija de Producto
• Nombre
• Cuidados
Accesorio de jardinería (hija de producto)
Artículo
Viveros
• Código
• Teléfono
• Dirección
• ¿Responsable? No, esto es una relación
Zona
• Nombre (clave)
Pedido
• Número: clave
• Fecha
• Unidades, precio de portes y descuento son atributos de una relación cuyo nombre todavía
no conocemos.
Cliente: habrá “Normales” y “Club VIP”
• DNI
• Dirección
• Teléfono
• Fecha de incorporación (solamente para el club VIP)
Relaciones:
“Empleado es Responsable De Vivero” tiene unos atributos de fecha de inicio y fin.
“Producto Se Distribuye en Zona”. Esto implica que hay un atributo en esta relacion llamado
Stock.
“Empleado Trabaja en Zona”
A la hora de almacenar el hecho de que un pedido consta de varios productos vamos a descubrir
que la relación ternaria no es la mejor opción ya que nos obligaría a que en un pedido solo apun-
tásemos un producto
VIP1 Ped1 Rosas
VIP1 Ped1 Tijeras
VIP1 Ped1 Semillas
Técnicamente, esta relación ternaria es capaz de guardar el hecho de que el cliente VIP1, en su pedido 1
compró “Rosas, Tijeras y Semillas”, sin embargo este modelo ternario nos está obligando a repetir datos.
Como conclusión la relación “Cliente hace pedido que consta de Artículos” no es la mejor opción, sino
que desglosaremos esto en dos binarias
“Vip Realiza Pedido” (esto implica que Pedido es débil)
2.4. Problemas 19
Bases de datos, Versión 1.1
El Departamento de Informática de la universidad necesita una base de datos para almacenar la informa-
ción concerniente a los proyectos de investigación tanto actuales como pasados en los que trabajan los
profesores y así poder llevar a cabo una gestiónmás eficiente. La información que se desea almacenar
corresponde a los siguientes supuestossemánticos.
En el departamento los profesores participan en proyectos de investigación caracterizados por un
código de referencia único, por un nombre, un acrónimo, un presupuesto total, el programa de
I+D que lo financia, una fecha de inicio y una fecha de finalización y una breve descripción de los
objetivos del proyecto.
En los proyectos trabajan profesores del departamento durante un período de tiempo, esdecir, una
fecha de inicio y una fecha de fin, pudiendo ocurrir que un profesor trabaje en elmismo proyecto
en varias épocas (f_ini, f_fin) diferentes.
Un profesor se identifica por su nombre y apellidos y se caracteriza por su despacho y teléfono
y puede trabajar en varios proyectos simultáneamente y en un proyecto de investigación trabajan
varios profesores. De todos los profesores que trabajan en el proyecto hay uno que es el inves-
tigador principal deproyecto que interesa conocer. Es importante tener en cuenta que el profesor
investigador del proyecto nunca varía a lo largo de la vida del proyecto de investigación.
Los profesores pueden ser doctores o no doctores, de tal manera que un profesor nodoctor siem-
pre tiene a un único profesor doctor como supervisor en un momento determinado,interesando
almacenar los supervisores y períodos de tiempo de la supervisión que ha tenido undeterminado
profesor no doctor.
En relación con la participación de los profesores en proyectosde investigación, el investigador
principal de un proyecto siempre tiene que ser un doctor.Por otro lado, los proyectos de investi-
gación producen una serie de publicaciones sobrelas que también interesa guardar información.
Una publicación se caracteriza por un número en secuencia dentro de cada proyecto de investi-
gación y se guardará el título y los profesores que la han escrito; las publicaciones son de dos
tipos, publicaciones en congresos y publicaciones en revista; de las primeras se almacenará el
nombre del congreso, su tipo (nacional ointernacional), la fecha de inicio y de fin, el lugar de cel-
ebración, país y la editorial que hapublicado las actas del congreso (si es que se han publicado);
de las publicaciones en revista interesa saber el nombre de la revista, la editorial, el volumen, el
número y las páginas de inicio y fin.
No solamente interesa conocer los profesores que han participado en las publicaciones de los
proyectos de investigación sino también las líneas de publicación que cubren estas publicaciones.
Una línea de investigación se identifica por un código, un nombre (por ejemplo,recuperación de
información multilingüe, bases de datos espacio-temporales, etc.) y un conjunto de descriptores
(por ejemplo, la línea de investigación bases de datos temporales puede tener como descriptores
Bases de Datos, SGBD Relacional, Dimensión temporal).
Los profesores tendrán asociados en la BD las líneas de investigación en las quetrabajan inclu-
so podría ocurrir que hubiera profesores que no tuvieran ninguna línea asignada.Así, tanto los
profesores doctores como los no doctores pueden escribir publicaciones sobre una o más líneas
de investigación y nos interesa saber sobre qué línea de investigación ha escrito un determinado
profesor en una publicación, teniendo en cuenta que un profesor queparticipa en una publicación
sólo escribe en el ámbito de una línea de investigación y que una determinada publicación puede
cubrir varias líneas de investigación
Solución: entidades
Proyecto
• código de referencia único
• un nombre
• un acrónimo
• un presupuesto total
• el programa de I+D que lo financia
• una fecha de inicio y una fecha de finalización
• y una breve descripción
Profesor
• Nombre y apellidos.
• Despacho y teléfono.
• ¿Investigador principal hijo de Profesor? Es mala idea porque usaríamos una entidad para
algo que aparecerá una sola vez.
• “Doctor” y “No doctor” sí pueden ser entidades hija.
Publicación.
• Número
• Título
• Profesores que lo escriben (esto será una relación)
• “En congreso” y “En revista” serán entidades hija.
◦ En congreso tiene los atributos: Tipo, nombre, fecha de inicio, de fin, lugar de cele-
bración, país y editorial.
◦ En revista tiene los atributos: nombre de revista, el volumen, editorial, páginas de inicio
y fin.
Línea
• Código
• Nombre
Descriptores:
• Nombre
2.4. Problemas 21
Bases de datos, Versión 1.1
Solución: relaciones
• A tener en cuenta: esta tabla ilustra que un diseño mejor habría sido tener dos relaciones
como “Se enfrenta con blancas” y “Se enfrenta con negras”. Aún así, habría que programar
Torneo (NombreTorneo, NombreFed, Periodicidad,Cuantia)
• NombreFed es clave ajena sobre Federación(Nombre)
Edición (Numero, NombreTorneo,NombreFed, Nombre,Apellidos)
• La pareja (NombreTorneo,NombreFed) es clave ajena sobre Tor-
neo(NombreTorneo,NombreFed)
• La pareja (Nombre,Apellidos) es clave ajena sobre Jugador(Nombre,Apellidos)
En este punto debemos reformar la tabla partida y dejarla así
• Partida (CódigoPartida, FechaInicio, Duración, NumeroEdicion, NombreTorneo, Nom-
breFederacion)
◦ El trío (NumEdicion, NombreTorneo, NombreFederacion) es clave ajena sobre Edi-
cion(NumEdicion,NombreTorneo,NombreFederacion)
Resuelto en la pizarra
2.6 Normalización
Cuando se elabora un diseño de tablas, puede ocurrir que aún siga existiendo mucha redundancia.
Al diseñar tablas se debe examinar la redundancia que pueda existir en ellas. Estas redundancias suelen
ser visibles a simple vista: Dado un CP se puede deducir la Población. Estas redundancias adoptan un
nombre muy concreto: “Dependencias funcionales” o tambien “implicaciones”.
A veces, las dependencias funcionales implican varios campos en conjunto. Supongamos una tabla como
esta
Jugador (Nombre,ap, país)
Cuando en una dependencia hay varios atributos se le llama “dependencia funcional completa”.
Para eliminar una dependencia crearemos una tabla separada de la tabla inicial.
En la nueva tabla pondremos estos campos: el implicante y los implicados
La clave de la nueva tabla es el implicante (o los implicantes, si hay varios)
En la tabla vieja se borran todos los implicados y el implicante se convierte en clave ajena sobre
la nueva tabla.
Recordemos un par de conceptos
Clave primaria: es un atributo (o pareja, o trío) que sabemos que no se va a repetir.
Clave candidata: es un atributo (o pareja) que PODRÍA ACTUAR COMO PRIMARIA pero no
lo hemos elegido.
Transitividad: supone que si “A implica B” y “B implica C”, automáticamente sabremos que “A
implica C”.
Una tabla está en 1FN si en cada atributo se prohíbe insertar más de un valor.
Una tabla está en segunda forma normal si todos los campos tienen dependencia completa respecto a la
clave.
Supongamos una base de datos con una tabla como esta
Compras(CodigoProveedor, CodigoProducto, NombreProducto, Cantidad).
En esta tabla es fácil observar que hay una dependencia funcional pero no completa con respecto a la
clave (CodigoProveedorProducto) sino parcial, de la forma “CodigoProducto implica Nombre”.
Una tabla está en 3FN si está en 2FN y además no hay dependencias transitivas.
2.6. Normalización 25
Bases de datos, Versión 1.1
Diseño físico
3.1 Introducción
Access crea automáticamente un campo llamado ID que actuará como clave primaria. Este campo ID
usará un tipo llamado “Autonumérico”
Dicho campo es un número entero
Se incrementa automáticamente cuando pasamos a otra fila.
Texto
Acepta letras, números y símbolos pero solo acepta conjuntos de longitud pequeña (255 símbolos máx-
imo)
27
Bases de datos, Versión 1.1
Memo
Fecha
Permite manejar datos relacionados con las fechas y con sus intervalos.
Numéricos
Se reservan para datos para los cuales se deseen hacer operaciones matemáticas.
Los tipos numéricos pueden concretarse aún más:
Byte: acepta números en el rango 0-255
Enteros cortos: números entre -32767 y 32768
Entero largo: a nivel interno usa 32 bits (-2^32 hasta 2^32)
Decimal: acepta decimales al nivel que le indiquemos
Simple: acepta negativos y decimales de precisión variable
Doble: acepta negativos y decimales muchísimo más grandes y con mucha más precisión decimal
En general la regla es: “cuanto más corto es el campo más rápido se procesa pero menos precisión
nos ofrece”
Sí/No
Se puede controlar la apariencia que tendrán los datos en pantalla, por ejemplo, una fecha puede
mostrarse como 13-2-85 o 13/2/1985
Formato de la fecha
En el formato de la fecha se deben usar tres símbolos básicos para manejar el día, el mes y el año,que
son respectivamente d, m y a
d-m-aa: Escribe algo como “1-3-81”
d-m-aaaa: Escribe algo como “1-3-1981”
d-mmm-aaaa: Escribe algo como “1-Mar-1981”
dd-mmm-aaaa: Escribe la fecha “01-Mar-1981”
dd-mm-aaaa: Escribe la fecha “01-03-1981”
dd/mm/aaaa: Escribe la fecha “01/03/1981”
dd/mmmm/aaaa: Escribe la fecha “01/Marzo/1981”
Formato de cadenas
Formato de números
Hemos dicho que el formato cambia la forma de mostrar las cosas en pantalla (pero no cambia como
se almacenan por dentro). Sin embargo a veces es importante intentar evitar que se almacenen datos
incorrectos.
Para indicar a Access las máscaras de entrada, usaremos estos códigos
0: Es obligatorio insertar una cifra en esa posición
L: Es obligatorio insertar una letra en esa posición
9: Es optativo insertar algo, pero si se hace que sea una cifra
?: Es optativo insertar algo, pero si se hace que sea una letra
A: Es obligatorio insertar algo aquí y puede ser una letra o un número.
a: Es optativo insertar algo aquí y puede ser una letra o un número.
Ejercicio: ¿como sería la máscara que permite a la gente insertar su DNI con o sin letra?
Solución: 90000000?
Ejercicio: ¿como sería la máscara de entrada de un campo login que puede tener 3-4 letras seguidas de
4-5 números?
Solución: la solución sería ?LLL00009 (se recomienda dejar los elementos optativos en las “esquinas”).
Ejercicio: ¿como sería la máscara de entrada de un campo password, donde se obliga a que la clave tenga
entre 8 y 12 símbolos que pueden ser letras o números?
Solución: AAAAAAAAaaaa
3.2.5 Título
Es un valor que Access puede insertar automáticamente para casos de tablas donde la mayor parte de
registros tienen el mismo valor.
Es más potente que una máscara de entrada, ya que permite indicar condiciones que los datos deben
cumplir antes de ser insertados
3.2.9 Requerido
Nos indica si es obligatorio que haya dentro del campo o si por el contrario puede estar vacío.
3.2.10 Indexado
Permite seguir utilizando un solo byte por símbolo a pesar de que utilicemos Unicode (que utiliza de 2
a 4 bytes por símbolo)
IME significa Input Method Editor, y especifica los diversos sistemas existentes para introducir símbo-
los. Es relevante solamente en casos como el uso de lenguajes asiáticos y similares.
Permite que Access procese de una forma especial diversos campos. Para ello debemos saber como
funciona el vocabulario XML de Microsoft
3.2.15 Alineación
Access denomina a este concepto “Relaciones”. Para indicar que un campo es clave ajena sobre otro, se
deberá acudir a este menú y arrastrar la clave ajena sobre la primaria.
Se denomina integridad referencial a la capacidad del SGBD de obligar a que los datos de una tabla
existan previamente en otra.
Cuando se conectan campos y la clave ajena es autonumérica se está cometiendo un error, ya que Access
intentaría cambiar los valores sin ceñirse a la clave primaria.
Al crear una clave ajena se pueden hacer cumplir dos condiciones extrar
1. Actualización en cascada: si alguien cambia la clave primaria, el que se marcó como clave ajena
cambiará automáticamente
2. Borrado en cascada: si alguien borra el registro de la clave primaria, los registros asociados en la
clave ajena se borrarán también. No siempre es necesario hacer esto.
3.4 MySQL
El comando para crear una base de datos: create database <nombre>. Sin embargo la creación de una
tabla es un proceso complejo.
create table publicacion
(
numero int,
titulo char(60)
);
use ... ;
drop table empleado;
create table empleado
(
dni char(10),
nombre varchar(60),
apellidos varchar(120),
primary key (dni)
);
Clave ajena
create table empleado
(
dni char(10),
3.4. MySQL 33
Bases de datos, Versión 1.1
nombre varchar(60),
apellidos varchar(120),
primary key (nombre, apellidos)
);
create table sueldos
(
dni char(10),
sueldo decimal(6,2),
primary key (dni),
foreign key (dni) references empleado (dni)
);
);
3.4. MySQL 35
Bases de datos, Versión 1.1
(
nombre varchar(80),
apellidos varchar(140),
primary key (nombre, apellidos),
foreign key (nombre, apellidos)
references profesor(nombre, apellidos)
);
);
Los “undo files” son archivos utilizados por el SGBD para anotar los hechos que van teniendo lugar
(por ejemplo, al sacar dinero de un cajero). Si algo va mal, el SGBD puede utilizar dichos ficheros para
Consultas SQL
4.1 Introducción
Las consultas, las sentencias SELECT se apoyan sobre dos conceptos matemáticos denominados
Algebra relacional
Cálculo relacional
La sentencia SELECT permite extraer datos de las tablas en base a condiciones muy diversas.
La operación más básica que podemos hacer es extraer todo lo que hay en una tabla.
select * from proveedores;
select * from partes;
select * from proyectos;
select * from suministra;
4.3 Condiciones
Muy a menudo no necesitaremos mostrar todos los datos de la tabla, sino solo algunos que se especifi-
carán mediante condiciones.
Si por ejemplo, deseáramos mostrar solo los proveedores cuya ciudad sede está en París haríamos algo
como esto.
select * from proveedores
where ciudad="Paris";
Otra posible consulta sería “mostrar todos los proveedores cuyo estado tiene el codigo 10”
select * from proveedores
where estado=10;
39
Bases de datos, Versión 1.1
Las condiciones pueden ser muy complejas, y se pueden construir utilizando los operadores AND y OR.
Por ejemplo, “mostrar todos los proveedores cuya ciudad es Londres y su estado es 10”.
select * from proveedores
where ciudad="Londres"
and estado=10;
No es obligatorio mostrar todos los campos, se pueden mostrar solamente algunos de ellos indicando su
nombre. Por ejemplo, “mostrar el nombre de proveedor y la ciudad de los proveedores cuyo estado sea
20”.
select nombreprov, ciudad
from proveedores
where estado=20;
La respuesta es que no se muestra nada. La condición está mal escrita ya que no puede haber un número
que sea menor de 10 y a la vez mayor de 20.
Mostrar los nombres de proveedores cuyo estado sea 10 y su ciudad Paris o Londres.
Un primer intento sería este .. code-block:: mysql
select nombreprov from proveedores where estado=10 and (ciudad=”Paris” or ciu-
dad=”Londres”);
Sin embargo, no funciona correctamente. La propia pregunta es ambigua
Una posibilidad es que la pregunta fuera así “Mostrar los nombres de proveedores cuyo estado sea
10 y (su ciudad Paris o Londres).”
La otra posibilidad es que la pregunta fuera así “Mostrar los nombres de proveedores cuyo (estado
sea 10 y su ciudad Paris) o Londres.”
Es importante recordar que cuando en una condición hay tres o más elementos de comparación puede
que sea necesario utilizar paréntesis.
Mostrar las partes rojas o verdes que pesen 17 o más.
Esta pregunta debe aclararse antes de resolverse.
Mostrar las partes siempre que pesen 17 o más y que luego cumplan una de estas dos: tener color
rojo o tener color verde.
“Mostrar las partes (rojas o verdes) que pesen 17 o más.”
Mostrar las partes que siendo verdes pesen 17 o más o si no que simplemente sean rojas.
Se denomina agregado a alguna función de tipo estadístico aplicada a un subconjunto de los datos de
una tabla.
4.4.1 Recuento
La función COUNT nos dice cuantas filas cumplen una cierta condición. No es obligatorio poner dicha
condición.
select count(*) from partes;
Si deseáramos una condición como por ejemplo “hacer el recuento de partes cuyo color sea Azul”
select count(*) from partes
where color="Azul";
4.4.2 Promedio
Esta función calcula la media aritmética de las filas que cumplan una cierta condición. Tampoco es
obligatorio poner la condición. La función promedio en SQL es AVG(*)
¿Cual es el peso medio de las partes?
select avg(peso) from partes;
Son operaciones que nos devuelven el valor más grande o más pequeño de entre los que cumplan una
condición.
Estas funciones en SQL son
MAX(campo-numérico)
MIN(campo-numérico)
¿Cual es peso más grande de alguna parte?
select max(peso) from partes;
4.4.4 Sumas
La operación SUM(campo-numérico) efectúa la suma de ese campo para las filas que cumplan una cierta
condición.
¿Cuantas partes en total ha suministrado el proveedor v1?
select sum(cantidad)
from suministra
where numprov="v1";
A veces no se hará una sola operación matemática sino muchas. En ese caso es muy importante indicar
a SQL en base a qué debe hacer los resultados, o lo que es lo mismo como agrupar antes de hacer las
operaciones.
En SQL se indicarán los grupos sobre los cuales se va a hacer cada operación mediante la cláusula
GROUP BY (campo). Además, al hacer un “group by” es obligatorio también seleccionar el campo por
el que se hacen los grupos.
La respuesta a una pregunta como:”¿Cual es la media de peso de las partes por color?”
select avg(peso), color
from partes
group by (color);
Si ahora deseamos mostrar solo aquellos cuyo recuento sea mayor o igual que 2 debemos añadir una
cláusula HAVING como esta
select count(*), ciudad
from proveedores
group by (ciudad)
having count(*)>=2;
El WHERE es una condición que se aplica antes de hacer los cálculos. Sin embargo, si una vez hechos
los cálculos no deseamos mostrarlos todos deberemos utilizar el HAVING.
“Mostrar cuantos tornillos hay en total”
Al hacer esta consulta se pueden cometer varios errores, como por ejemplo este, que muestra todas las
partes
select count(*), nombreparte from partes
group by nombreparte;
Esto no es exactamente un error, sino más bien una trampa: se hizo el recuento a mano y se hizo trampa
Error: En este caso se ha confundido el where con el having
select count(*), nombreparte from partes
group by nombreparte having nombreparte="Tornillo";
Pregunta: ¿Podríamos quitar el group by? Respuesta: aunque en este caso sí podríamos no se debe hacer.
Cuando nos pidan una operación matemática por grupos, debemos poner group by
select count(*), nombreparte from partes
where nombreparte="Tornillo"
group by nombreparte
En ocasiones la información que nos pidan puede que esté dispersa por distintas tablas. SQL ofrece un
mecanismo para “conectar” tablas y así poder hacer las comparaciones que nos pidan.
Por ejemplo, si nos piden el nombre de las partes suministradas en una cantidad >=500 descubriremos
que
El nombreparte está en la tabla partes
La cantidad esta en la tabla suministra
Las tablas partes y suministra tienen un campo en común, el campo numparte
Utilizando una cláusula denominada “inner join” SQL puede establecer las correspondencias correctas
entre dos o más tablas.
Cruce de datos entre las tablas partes y suministra basándonos en que el campo numparte de suministra
debe ser igual que el numparte de suministra
De aqui sacamos solamente los campos que nos piden
2. Deseamos saber los numeros de proveedor que realizan suministros pero sin que se muestren
repetidos
select distinct numprov from suministra;
3. Sumar las cantidades que se han suministrado (¿cuantas piezas se han suministrado?)
select sum(cantidad) from suministra;
7. Mostrar los numeros de parte suministrados en una cantidad total mayor o igual que 1000
select sum(cantidad), numparte
from suministra
group by (numparte)
having sum(cantidad)>=1000;
8. Mostrar la suma de las partes suministradas por v1, v2, o v3 en una cantidad mayor de 550
select sum(cantidad),numparte
from suministra
where numprov=’v1’ or numprov=’v2’ or numprov=’v3’
group by (numparte)
having sum(cantidad)>550;
4.7 Subconsultas
Al hacer consultas hemos observado que hay cláusulas que permiten establecer condiciones.
Al hacer las condiciones es posible que necesitemos hacer una “subpregunta” y que la sentencia SE-
LECT quede algo así
select ....
from ...
where campo>(select max(cantidad) from suministra)
Supongamos una pregunta como la siguiente: “¿Cuales son los nombres de parte que pesan lo mismo
que la parte más pesada?”
Podemos sacar el peso maximo con esta consulta
select max(peso) from partes;
Dentro de las subconsultas, aparte de las comparaciones típicas como >, >=, <>, <=, <, etc... existen
otros elementos para hacer comparaciones
EXISTS: nos dará las filas donde exista alguna fila que cumpla la condición
ALL: la condición deben cumplirla todas las filas
12. ¿Qué nombres de parte corresponden a una pieza azul o almacenada en París?
select nombreparte from partes
where color="Azul" or ciudad="Paris"
13. ¿Qué colores tienen las distintas partes que no sean tornillos?
select * from partes
where nombreparte<>"Tornillo";
15. ¿Qué nombres de parte se suministran en una cantidad mayor o igual de 400?
select nombreparte,cantidad
from partes inner join suministra
on partes.numparte=suministra.numparte
where cantidad>=400;
4.7. Subconsultas 47
Bases de datos, Versión 1.1
Cuyo resultado es que se cruzan los datos correctamente y se obtiene una tabla como esta
numprov numparte numproyecto cantidad numprov nombreprov estado ciudad
v1 p1 y1 200 v1 Smith 20 Londres
v1 p1 y4 700 v1 Smith 20 Londres
v2 p3 y1 400 v2 Jones 10 Paris
v2 p3 y2 200 v2 Jones 10 Paris
v2 p3 y3 300 v2 Jones 10 Paris
v2 p3 y4 500 v2 Jones 10 Paris
v2 p3 y5 600 v2 Jones 10 Paris
v2 p3 y6 400 v2 Jones 10 Paris
v2 p3 y7 600 v2 Jones 10 Paris
v2 p5 y2 100 v2 Jones 10 Paris
v3 p3 y1 200 v3 Blake 30 Paris
v3 p4 y2 500 v3 Blake 30 Paris
v4 p6 y3 300 v4 Clarke 20 Londres
v4 p6 y7 300 v4 Clarke 20 Londres
v5 p1 y4 100 v5 Adams 30 Atenas
v5 p2 y2 200 v5 Adams 30 Atenas
v5 p2 y4 100 v5 Adams 30 Atenas
v5 p3 y4 200 v5 Adams 30 Atenas
v5 p4 y4 800 v5 Adams 30 Atenas
v5 p5 y4 400 v5 Adams 30 Atenas
v5 p5 y5 500 v5 Adams 30 Atenas
v5 p6 y2 200 v5 Adams 30 Atenas
v5 p6 y4 500 v5 Adams 30 Atenas
Si ponemos la condición que nos falta el ejercicio se resuelve correctamente
select nombreprov,cantidad
from proveedores inner join suministra
on proveedores.numprov=suministra.numprov
where cantidad<300
order by nombreprov desc;
select count(numprov)
from suministra
where cantidad<300;
18. ¿Qué nombre tienen las partes suministradas en una cantidad total de 550 o más?
select sum(cantidad), partes.numparte,nombreparte
from suministra
inner join partes
on suministra.numparte=partes.numparte
group by (partes.numparte)
having sum(cantidad)>=550;
20. Queremos saber los proveedores que están ubicados en el mismo sitio que alguna parte.
Examinemos la tabla partes
numparte nombreparte color peso ciudad
p1 Tuerca Rojo 12 Londres
p2 Perno Verde 17 Paris
p3 Tornillo Azul 17 Roma
p4 Tornillo Rojo 14 Londres
p5 Leva Azul 12 Paris
p6 Engranaje Rojo 19 Londres
Examinemos la tabla proveedores
numprov nombreprov estado ciudad
v1 Smith 20 Londres
v2 Jones 10 Paris
v3 Blake 30 Paris
v4 Clarke 20 Londres
v5 Adams 30 Atenas
Se puede comprobar que no nos piden para nada datos de la tabla suministra. Lo único que se necesita
es emparejar las filas donde las ciudades sean iguales.
select nombreprov,nombreparte,partes.ciudad
from partes
inner join proveedores
on partes.ciudad=proveedores.ciudad;
4.7. Subconsultas 49
Bases de datos, Versión 1.1
25. Obtener el nombre de los provedores, el nombre de parte que suministran y la cantidad en que
suministran
select nombreprov, nombreparte,cantidad
from proveedores
inner join suministra
on
suministra.numprov=proveedores.numprov
inner join partes
on
suministra.numparte=partes.numparte
27. Mostrar suministros donde el proveedor y la parte hayan resultado ser de una ciudad distinta
select suministra.numprov, suministra.numparte,
proveedores.ciudad, partes.ciudad
from suministra
inner join proveedores
on proveedores.numprov=suministra.numprov
inner join partes
on partes.numparte=suministra.numparte
where
proveedores.ciudad<>partes.ciudad;
28. ¿Cuantos proveedores suministran partes rojas o que pesen 12 gramos o más?
Trozo 1: partes rojas
select numparte from partes where color="Rojo"
30. ¿De qué ciudad de proveedor ha salido la cantidad más grande de suministros?.
Esta pregunta podría entenderse de dos formas “Obtener la cantidad más grande suministrada y la ciudad
del proveedor correspondiente”
En primer lugar necesitamos cruzar “proveedores” y suministra
4.7. Subconsultas 51
Bases de datos, Versión 1.1
Sin embargo esto no funciona porque cualquier operación de agregado no involucra a ninguna fila. De
hecho esa consulta nos devuelve un máximo correcto pero no nos devuelve la ciudad asociada, sino la
primera que encuentra.
Hay que encontrar otra forma de expresar esta consulta
select ciudad
from proveedores inner join suministra
on
suministra.numprov=proveedores.numprov
where cantidad=
(
select max(cantidad) from suministra
);
having sum(cantidad)>=
ALL
(
select sum(cantidad)
from suministra
group by (numprov)
)
;
33. Obtener todos los detalles de todos los proyectos ubicados en Londres.
select nombreprov, nombreparte,nombreproyecto,cantidad
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
4.7. Subconsultas 53
Bases de datos, Versión 1.1
35. Obtener los datos de los proyectos que usan partes en cantidades comprendidas entre 300 y 750.
select distinct proyectos.*
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
where
( cantidad>=300 ) and ( cantidad<=750 )
order by proyectos.numproyecto
;
37. Obtener los colores de las partes que se han suministrado por V1.
select partes.color from suministra
inner join
partes
on partes.numparte=suministra.numparte
where numprov=’v1’;
39. Obtener las parejas de nombres de ciudad tales que un proveedor ubicado en la primera ciudad
suministra a algún proyecto ubicado en la segunda ciudad.
select proveedores.ciudad, proyectos.ciudad
from suministra
inner join proveedores
on
suministra.numprov=proveedores.numprov
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto;
40. Obtener los códigos de parte suministrados a los proyectos ubicados en la misma ciudad del
proveedor.
select suministra.numparte
from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
inner join proveedores
on
suministra.numprov=proveedores.numprov
where
proveedores.ciudad=proyectos.ciudad;
41. Obtener los códigos de proyecto a los que suministra un proveedor que no está en la misma ciudad.
select suministra.numproyecto
from suministra
inner join proveedores
on
proveedores.numprov=suministra.numprov
inner join proyectos
on
proyectos.numproyecto=suministra.numproyecto
where
proyectos.ciudad<>proveedores.ciudad;
43. Obtener los códigos de parte suministrados a cualquier proyecto que esté ubicado en Londres
select numparte from suministra
inner join proyectos
on
suministra.numproyecto=proyectos.numproyecto
where
proyectos.ciudad="Londres";
44. Obtener los códigos de proyecto que usan al menos una parte suministrada por el proveedor V1
4.7. Subconsultas 55
Bases de datos, Versión 1.1
En segundo lugar queremos saber los proyectos cuyas partes sean alguna de las que hemos extraído
antes.
select numproyecto from suministra
where numparte in
(
select numparte from suministra
where numprov=’v1’
);
45. Obtener los códigos de proveedor que suministran al menos una parte roja.
Seleccionamos las partes cuyo color es rojo
select numparte from partes where color="Rojo";
Ahora, en la tabla suministra sacamos las filas donde la parte sea alguna de las extraídas antes
select numprov from suministra
where numparte in
(
select numparte from partes
where color="Rojo"
);
46. Obtener los códigos de proyecto cuya ciudad es la primera en la lista de ciudades.
Seleccionamos la ciudad más pequeña
select min(ciudad) from proyectos;
47. Obtener los códigos de proyecto a los que se suministra la parte P1 en una cantidad promedio
igual o superior a la cantidad más grande que se suministra al proyecto Y1.
Extraemos la cantidad más grande del proyecto “y1”
select max(cantidad) from suministra
where numproyecto="y1";
Al haber una condición para el promedio deberemos poner algo como esto
select numproyecto,avg(cantidad) from suministra
where numparte=’p1’
group by numproyecto
having avg(cantidad)>=
(
select max(cantidad) from suministra
where numproyecto="y1"
);
48. Obtener los códigos de proveedor de los que suministran la parte P1 a algún proyecto en una
cantidad superior a la cantidad promedio de la parte P1 para ese proyecto.
Podemos empezar intentando sacar la media de partes p1 para cada proyecto
select numproyecto, avg(cantidad) from suministra
where numparte=’p1’
group by numproyecto;
49. Obtener los códigos de proyecto a los que ningún proveedor de Londres suministra una parte roja.
Primero averiguamos los proveedores de Londres que suministran partes rojas.
select suministra.numprov
from suministra
inner join partes
on partes.numparte=suministra.numparte
inner join proveedores
on proveedores.numprov=suministra.numprov
where
proveedores.ciudad="Londres"
and
partes.color="Rojo";
Ahora examinamos la tabla suministra y comprobamos que el proveedor no esté en el conjunto devuelto
por la consulta anterior
4.7. Subconsultas 57
Bases de datos, Versión 1.1
50. ¿Hay algún proveedor que suministre la misma parte a TODOS los proyectos?
Para conseguir la solución a este problema se deben utilizar algunas características de los cuantifi-
cadores.
Replanteamos la pregunta
“se desea saber los proveedores donde para todos los proyectos existe una misma parte suministrada”
o más desarrollado
“proveedores (de la tabla suministra) donde para todo proyecto (de la tabla proyectos) existe un sumin-
istro donde el codigo de proveedor es dicho proveedor y la parte es la misma parte que mirábamos en
suministra”
select numprov from suministra as s1
where not exists
(
select numproyecto from proyectos
where numproyecto not in
(
select numproyecto from suministra as s2
where
s1.numparte=s2.numparte
and
s1.numprov=s2.numprov
);
51. Obtener los códigos de proyecto que usan todas las partes suministradas por el proveedor v1
“Obtener los códigos de proyecto donde para toda parte de la tabla suministra existe una parte sumin-
istrada por v1”
Obtener el conjunto de parte suministradas por v1.
select numparte from suministra
where numprov=’v1’;
Las filas de la tabla suministra donde para toda parte de v1 existe alguna fila asociada
52. (Para nota) Obtener los pares de proveedores V1 y V2 que suministren EXACTAMENTE el mis-
mo conjunto de partes.
La pregunta podría replantearse como
“obtener parejas de proveedores donde para toda parte de un proveedor de la primera tabla existe otro
proveedor distinto tal que la parte es la misma que la parte del primero”.
Una vez que se han insertado datos, estos no son inmutables. Pueden cambiarse valores de las filas o
incluso pueden borrarse las filas.
Estas operaciones se hacen con las sentencias UPDATE y DELETE.
Para cambiar valores se hace lo siguiente
UPDATE <TABLA> SET <CAMPO>=VALOR WHERE <CONDICION>
Por ejemplo, si quisiéramos hacer que en la tabla partes se cambiara la ciudad Londres por Madrid
haríamos algo como esto
UPDATE partes SET ciudad="Madrid"
WHERE ciudad="Londres";
Poner en la tabla partes el peso a 30 en todas las partes cuyo peso sea mayor que 16;
update partes set peso=30
where peso>16;
Programación
5.1 Introducción
Los elementos de los lenguajes de programación son muy similares entre sí y el cambio de lenguaje
solamente supone la modificación de ciertos hábitos.
En el entorno de las bases de datos se pueden encontrar programas que actúen mediante dos mecanismos
distintos. Estos dos mecanismos se definen como
Procedimientos almacenados: residen en el propio servidor de bases de datos.
Programas externos: utilizando algún mecanismo los programas externos se comunican con el
servidor para intercambiar datos mediante un lenguaje de programación cualquiera.
Entre los mecanismos de comunicación más utilizados encontramos ODBC (Open DataBases Commu-
nication). Este estándar especifica claramente a servidores y cliente como tienen que dar o pedir datos.
Una versión modificada de ODBC es JDBC que ha modernizado el estándar pero solo sirve para pro-
gramas Java.
5.2.2 Variables
Una variable es una posición de memoria con nombre. Normalmente las variables conllevan un tipo que
restringe lo que podemos almacenar en ella.
En MySQL las variables se declaran con la palabra clave DECLARE.
Los tipos utilizables con las variables son los mismos que tiene MySQL.
61
Bases de datos, Versión 1.1
Los procedimientos en MySQL actúan igual que las funciones en Java con las diferencias en la sintaxis.
El primer problema que aparece en los procedimientos MySQL viene dado por el hecho de que los
procedimientos a veces interfieren con el delimitador ”;”. Para evitarlo, debemos avisar a MySQL de
que durante un tiempo cambiaremos de delimitador, para ello se usa la siguiente sentencia
Dentro de “código” podrán ir sentencias que terminarán de forma normal, con el punto y coma ”;”
El problema viene dado porque el intérprete de MySQL intenta procesar todo lo que haya hasta llegar
a un punto y coma. Si no cambiásemos el delimitador, se ejecutaría la definición del procedimiento sin
haber encontrado un “end” y todo fallaría.
Ejercicio: crear un procedimiento que acepte una cantidad c y que seleccione todos los suministros cuyo
campo cantidad sea mayor que c
delimiter //
//
delimiter ;
Ejercicio: crear un programa que acepte un color co y una ciudad ci y que busque todas las partes cuyo
color sea ese co pasado y la ciudad ese ci pasado. Co y ci son parámetros y NO LLEVAN COMILLAS
delimiter //
create procedure Color_parte
(color_pasado varchar(20),
ciudad_pasada varchar(20) )
begin
select * from partes
where color=color_pasado
and
ciudad=ciudad_pasada;
end
//
delimiter ;
Ejercicio: crear un procedimiento que permita sumar la cantidad de partes suministradas cuyo color sea
el mismo que un cierto color pasado
drop procedure suministradas_color;
delimiter //
begin
select sum(cantidad)
62 Capítulo 5. Programación
Bases de datos, Versión 1.1
from suministra
inner join partes
on
suministra.numparte=partes.numparte
where color=color_pasado;
end
//
delimiter ;
call suministradas_color("Rojo");
call suministradas_color("Gris");
begin
select * from suministra inner join partes
on suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and
cantidad>cantidad_pasada;
end
//
delimiter ;
IF (<comparacion>) THEN
BEGIN
<sentencias>
END
ELSE
BEGIN
END
END IF;
Ejemplo: crear un procedimiento que extraiga las filas de la tabla suministra que cumplan cierta condi-
cion sobre la cantidad. Si el usuario pasa un simbolo “>” el procedimiento nos devuelve las filas mayores
que cierta cantidad. Si no pasa un “<” nos devuelve las filas con una cantidad menor que la pasada
drop procedure selector_v2;
delimiter //
//
delimiter ;
Ejercicio:crear un procedimiento que dados los parámetros siguientes compruebe cuantas partes con un
cierto nombre tienen una cantidad menor o mayor que una cierta cantidad pasada
nombre_parte_pasado
cantidad_pasada
operacion
drop procedure selector_v3;
delimiter //
64 Capítulo 5. Programación
Bases de datos, Versión 1.1
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and
cantidad>cantidad_pasada;
end;
else
begin
select * from suministra inner join
partes on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and
cantidad<cantidad_pasada;
end;
end if;
end;
//
delimiter ;
Ejercicio: ampliar el programa anterior para que soporte búsquedas utilizando los comparadores “<”,
“>”, “>=”, “<=”, “=” y “<>”.
El programa anterior puede resolverse utilizando sentencias if-then-else anidadas, sin embargo es poco
práctico y difícil de ampliar.
La sintaxis de la sentencia case es la siguiente
CASE <variable>
WHEN ">" THEN
BEGIN
END;
WHEN ">=" THEN
BEGIN
END;
WHEN "<" THEN
BEGIN
END;
...
ELSE
BEGIN
END;
END CASE;
Basándonos en esta sintaxis, una posible solución al problema anterior sería esta
drop procedure selector_v4;
delimiter //
create procedure selector_v4
( nombre_parte_pasada varchar(11),
cantidad_pasada int,
operacion varchar(1) )
begin
case operacion
when ">" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad>cantidad_pasada;
end;
when ">=" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad>=cantidad_pasada;
end;
when "<>" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad<>cantidad_pasada;
end;
when "<" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad<cantidad_pasada;
end;
when "<=" then
begin
select * from suministra
inner join partes
on
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad<=cantidad_pasada;
end;
when "=" then
begin
select * from suministra
inner join partes
on
66 Capítulo 5. Programación
Bases de datos, Versión 1.1
suministra.numparte=partes.numparte
where
nombreparte=nombre_parte_pasada
and cantidad=cantidad_pasada;
end;
else
begin
select ("Operacion no reconocida");
end;
end case;
end;
//
delimiter ;
Ejercicio: crear un programa que acepte un nombre de parte,luego dos ciudades C1 y C2 y luego un
comparador que puede ser “AND” o “OR”. El programa debe decirnos las partes que pertenecen a las
dos ciudades o a una de ellas.
drop procedure comparador;
delimiter //
case operador
when "AND" then
begin
select * from partes as p1, partes as p2
where p1.nombreparte=nombre_parte_pasada
and
p2.nombreparte=nombre_parte_pasada
and (p1.ciudad=c1_pasada
and p2.ciudad=c2_pasada);
end;
when "OR" then
begin
select * from partes as p1, partes as p2
where p1.nombreparte=nombre_parte_pasada
and
p2.nombreparte=nombre_parte_pasada
and (p1.ciudad=c1_pasada
or p2.ciudad=c2_pasada);
end;
else
begin
select ("Escriba OR o AND (mayúsculas)");
end;
end case;
end
//
delimiter ;
Utilizando la sentencia WHILE podemos repetir una tarea que se repita un cierto número de veces por
medio de una variable.
La sintaxis de WHILE es la siguiente
set variable_control=0;
WHILE (<condicion>) DO
...
<sentencias>
..
set variable_control=variable_control+1;
END WHILE;
Ejercicio resuelto: hacer un programa MySQL que imprima los 10 primeros números pares.
drop procedure pares;
delimiter //
//
delimiter ;
5.3.4 Cursores
Un cursor es un puntero que apunta a la primera fila del resultado de una consulta. Podemos ir ha-
ciendo avanzar el puntero y procesar cada fila por separado. Podemos dejar de procesar filas cuando lo
deseemos, sin que sea obligatorio examinar todos los resultados.
No se puede declarar variables nuevas despues de un cursor. Es decir, esto no es válido
declare un_cursor cursor for...
declare contador int;
Esto sí es válido
declare contador int;
declare un_cursor cursor for...
68 Capítulo 5. Programación
Bases de datos, Versión 1.1
CLOSE nombre_cursor;
Ejercicio: extraer los proveedores que han recibido las 5 cantidades más grandes de suministros.
drop procedure mejores_clientes;
delimiter //
open cur1;
set contador=0;
while (contador<5) do
fetch cur1 into num_prov_sacado, cantidad_sacada;
select (num_prov_sacado);
select (cantidad_sacada);
set contador=contador+1;
end while;
close cur1;
end;
//
delimiter ;
Ejercicio: hacer un programa que saque las 2 partes de más peso de la tabla partes.
La consulta para este ejercicio sería:
select * from partes order by peso desc;
Y el procedimiento sería
drop procedure mayores_pesos;
delimiter //
create procedure mayores_pesos()
begin
declare contador int;
declare peso_extraido int;
declare ciudad_extraida varchar(15);
declare cur1 cursor for
select ciudad,peso from partes order by peso desc;
open cur1;
set contador=0;
while (contador<2) do
begin
fetch cur1 into ciudad_extraida,
select (ciudad_extraida),(peso_extraido);
set contador=contador+1;
end;
end while;
close cur1;
end;
//
delimiter ;
Y la solución sería
drop procedure suma_filas;
delimiter //
create procedure suma_filas()
begin
declare contador int;
declare suma int;
declare cantidad_extraida int;
declare cur1 cursor for
select cantidad from suministra
order by cantidad asc;
open cur1;
set suma=0;
set contador=0;
while contador<5 do
fetch cur1 into cantidad_extraida;
set suma=suma+cantidad_extraida;
set contador=contador+1;
end while;
close cur1;
select suma;
end;
//
delimiter ;
Si un procedimiento tiene que devolver cosas puede hacerlo utilizando parámetros en la cabecera que
hayan sido etiquetados como “out”.
drop procedure suma_filas;
delimiter //
create procedure suma_filas(out suma_devuelta int)
begin
declare contador int;
declare suma int;
declare cantidad_extraida int;
declare cur1 cursor for
select cantidad from suministra
order by cantidad asc;
open cur1;
set suma=0;
set contador=0;
while contador<5 do
fetch cur1 into cantidad_extraida;
70 Capítulo 5. Programación
Bases de datos, Versión 1.1
set suma=suma+cantidad_extraida;
set contador=contador+1;
end while;
close cur1;
set suma_devuelta=suma;
end;
//
delimiter ;
Ejercicio: realizar un procedimiento que devuelva en una variable la ciudad del proveedor con una
cantidad total (sumar) de suministros mayor.
La consulta sería algo así
select sum(cantidad),suministra.numprov,
ciudad from suministra
inner join proveedores
on suministra.numprov=proveedores.numprov
group by numprov
having sum(cantidad)>=ALL
(
select sum(cantidad)
from suministra
group by numprov
);
open cur1;
fetch cur1 into suma, num_proveedor,c_devuelta;
set ciudad_devuelta=c_devuelta;
close cur1;
end;
//
delimiter ;
5.4 Funciones
//
delimiter ;
Ejercicio: construir una función que devuelva la suma total de cantidades de la tabla suministra
La consulta sería así:
select sum(cantidad) from suministra;
Y la función
drop function suma_suministra;
delimiter //
create function suma_suministra() returns int
begin
declare suma int;
declare cur1 cursor for
select sum(cantidad) from suministra;
open cur1;
fetch cur1 into suma;
close cur1;
return suma;
end;
//
delimiter ;
set @s=suma_suministra();
La primera función de utilidad es la función CONCAT. Este trozo de código une dos cadenas en una sola
set @cadena1=CONCAT(apellido, nombre);
Hacer una función que devuelva el nombre de la pieza y el color en una sola cadena. Se debe devolver
la pieza con un peso mayor.
72 Capítulo 5. Programación
Bases de datos, Versión 1.1
La solución sería:
delimiter //
create function pieza_mayor_peso() returns varchar(25)
begin
declare cadena varchar(25);
declare nombre_pieza varchar(10);
declare color_pieza varchar(10);
declare cur1 cursor for
select nombreparte, color from partes
where peso=( select max(peso) from partes );
open cur1;
fetch cur1 into nombre_pieza, color_pieza;
set cadena=CONCAT(nombre_pieza, ":", color_pieza);
return cadena;
close cur1;
end;
//
delimiter ;
Hay una pareja de funciones llamadas LEFT y RIGHT, que nos permiten extraer trozos de las cadenas.
Por ejemplo, la función LEFT(peso, 1) nos devuelve la primera letra del campo peso.
Ejercicio: construir una función que nos devuelva la pieza de mayor peso con la letra inicial del color
entre paréntesis (es decir, se debe devolver algo como “Engranaje (R)”)
Para resolver este ejercicio era necesario utilizar la función LEFT (cadena, longitud). Esta función nos
devuelve un trozo de la cadena que mide lo que diga el parámetro longitud.
Existe una variante que extrae trozos desde el lado derecho y que se llama RIGHT (cadena, longitud).
drop procedure pieza_pesada_inicial;
delimiter //
//
delimiter ;
Ejercicio: construir una función que nos devuelva el codigo de proyecto con una cantidad de sumin-
istros menor. Por problemas de integración con otra base de datos necesitamos que se devuelva todo en
mayúsculas.
Para resolver esto existe una función que convierte una cadena a su equivalente en mayúsculas.
drop function proveedor_minimo;
delimiter //
//
delimiter ;
Ejercicio: crear un procedimiento que acepte una cadena como parámetro. El procedimiento deberá
mostrar todas las partes de la tabla partes cuyo nombre contenga la subcadena pasada como parámetro.
Es decir, podemos hacer algo como ésto
CALL buscar("To");
En general, la búsqueda de secuencias, cadenas o patrones es algo muy común pero muy sencillo de
resolver con algunas funciones.
La función INSTR() permite comprobar si una cierta subcadena está dentro de una cadena.
Existe un operador llamado LIKE que permite hacer búsquedas “difusas”.
Por ejemplo, se puede hacer una búsqueda como esta
select * from partes
where nombreparte LIKE "uer%";
delimiter //
74 Capítulo 5. Programación
Bases de datos, Versión 1.1
end;
//
delimiter ;
Ejercicio: se desea crear un procedimiento que permita marcar como obsoletas ciertas partes de la tabla
partes. Para ello, el usuario ejecutará un procedimiento como este
call marcar_obsoleta("To");
Este procedimiento CAMBIARÁ los nombres de parte de la tabla partes poniéndoles un asterisco al
principio. Para resolverlo será necesario manejar correctamente la condición de NOT FOUND para un
cursor. Además, necesitamos un procedimiento principal que construya el patrón y que luego llame al
procedimiento auxiliar que actualiza las filas.
drop procedure marcar_obsoletas;
drop procedure actualizar;
delimiter //
end;
//
delimiter ;
Ejercicio: crear un procedimiento que indique la desviación media de los pesos de las partes.
drop procedure desviaciones_medias;
delimiter //
//
delimiter ;
Aparte de la función ABS, que calcula el valor absoluto se pueden encontrar otras funciones de utilidad
como las siguientes:
CEIL (valor): Redondear el valor hacia arriba.
FLOOR (valor): Redondea hacia abajo.
ROUND (valor, decimales): si hacemos ROUND (3.6576, 2) nos devolvería el valor 3.66
76 Capítulo 5. Programación
Bases de datos, Versión 1.1
open cur1;
fetch cur1 into cuantos;
close cur1;
open cur2;
set cuantos=ceil(cuantos/2);
set contador=0;
while (contador<cuantos) do
fetch cur2 into peso_extraido;
set contador=contador+1;
end while;
set mediana=peso_extraido;
close cur2;
end;
//
delimiter ;
Crear una función que nos devuelva “sí” si hay la misma cantidad de partes rojas que de proyectos de
Atenas. Si no es así debe devolver “no”.
drop function cuantos;
delimiter //
if (cuantos_rojos=cuantos_atenas) then
return "SI";
else
return "NO";
end if;
close cur1;
close cur2;
end;
//
delimiter ;
9 begin
10 insert into proyectos
11 values (codigo_proyecto,nombre_proyecto,"Madrid");
12 end;
13
14 //
15
16 delimiter ;
78 Capítulo 5. Programación
CAPÍTULO 6
Administración
6.1 Introducción
lo que es potencialmente inseguro, ya que es posible capturar tramas en redes y obtener contraseñas.
Si se desea acceder a otro host distinto (tal vez un remoto) se debe hacer lo siguiente:
79
Bases de datos, Versión 1.1
6.2.3 Hashes
Un hash es un cálculo que se hace sobre una secuencia de datos que se utiliza para asegurar la integridad
de la secuencia de datos.
En MySQL 4.1 se cambió el sistema. Los nuevos hashes se almacenan con un asterisco delante.
MySQL tiene un sistema interno que controla quien puede hacer qué. Se debe tener en cuenta que
MySQL tiene dos barreras
1. La primera barrera se da en la conexión: se debe disponer de un usuario y de una clave.
2. La segunda barrera se comprueba cada vez que el usuario escribe una sentencia.
Se debe tener cuidado porque a veces los cambios en los permisos no se ejecutan inmediatamente. Si
observamos que esto está ocurriendo podemos lanzar el comando siguiente:
FLUSH PRIVILEGES;
Para ver los permisos concedidos al usuario que utilizamos podemos lanzar este comando
show grants;
A partir de ahora debemos recordar que un usuario no es solamente un login, sino también un sitio desde
el que se conecta. Estos dos usuario NO SON IGUALES
80 Capítulo 6. Administración
Bases de datos, Versión 1.1
’pepito’@’localhost’
’pepito’@’10.9.0.0/255.255.0.0’;
’pepito’@’sede-a.empresaacme.com’;
Se puede observar que hay dos usuarios llamados root@localhost y root@127.0.0.1. Son usuarios dis-
tintos y ambos tienen la clave vacía. No deben tenerse SGBD con la clave de root vacía.
Además la instalación por defecto también crea un usuario vacío y sin contraseña que permite conectarse
sin clave.
Para borrar un usuario se usa el comando DROP USER
DROP USER ’’@’localhost’;
Si un cambio no tiene lugar es posible que los cambios no se hayan volcado en el sistema de MySQL.
Podemos forzar a que los cambios tengan efecto usando este comando
FLUSH PRIVILEGES;
Se debe tener en cuenta que para poder conectar a una base de datos remota debemos disponer del
usuario con el host correspondiente.
¿Qué ocurre si aparentemente podemos entrar como dos posible usuarios distintos?. Supongamos que
nos conectamos desde la IP 10.9.0.200 con el usuario root y en MySQL hay dos usuarios (el % significa
“cualquier cosa”).
usuario host password
root 10.9.0.200 sesamo
root % 12341234
La regla es que cuando un usuario se conecta y se le pueden aplicar dos o más reglas se utiliza siempre
la más restrictiva.
Para crear un usuario debemos especificar su login y su host. El host podría ser ‘ %’.
create user ’dam1’@’10.9.0.0/255.255.0.0’
identified by ’sesamo’;
create user ’dam1’@’10.9.0.254’
identified by ’12341234’;
create user ’dam1’@’ %’
identified by ’6789’;
En ocasiones un usuario puede haber olvidado su clave o simplemente se desea renovar la misma por
una política de seguridad.
ESTO ES UN ERROR
set password for ’dam1’@’10.9.0.0/255.255.0.0’ = ’12345678’;
Aparte de los permisos SELECT, INSERT, UPDATE Y DELETE, CREATE, CREATE INDEX, CRE-
ATE VIEW
Ejercicio: diseñar un esquema de seguridad para dar respuesta a las siguientes necesidades de acceso a
datos.
Se necesita dar acceso a dos usuarios que puedan seleccionar datos de cualquier tabla que exista
en la base de datos proyectos.
De uno de los usuarios sabemos su IP (preguntar al compañero). El otro usuario puede provenir
de cualquier punto de la red 10.9.xxx.xxx.
Existe un usuario admin que puede provenir de cualquier punto de la red 10.9 y que puede hacerlo
todo con cualquier tabla de la base de datos proyectos.
Extra: se desea que el usuario admin tenga a su vez permisos para conceder permisos.
Al crear un usuario puede ser interesante limitar la cantidad de actividad que dicho usuario ejecuta por
hora.
Al crear los usuarios con CREATE USER se pueden indicar algunas limitaciones como las siguientes
82 Capítulo 6. Administración
Bases de datos, Versión 1.1
with max_queries_per_hour 8
with max_connections_per_hour 3
with max_updates_per_hour 2
;
6.6 Vistas
Una vista es un trozo extraído de una tabla en base a una consulta. Las vistas pueden utilizarse para
restringir aún más la cantidad de información que pueden ver los usuarios.
Antes de crear una vista se debe tener muy clara la consulta que se va a aplicar. Por ejemplo, si deseamos
tener por separado los datos de Paris sin incluir el estado podríamos crear una vista como esta:
CREATE VIEW PROV_PARIS AS
SELECT NUMPROV,NOMBREPROV,CIUDAD
FROM PROVEEDORES
WHERE CIUDAD="Paris";
Ejercicio: los administradores de la base de datos de proyectos necesitan establecer una configuración
de seguridad de acuerdo a las siguientes caracteristicas
Existe un usuario admin que puede conectarse desde cualquier punto de la red 10.9 que puede
hacer lo siguiente
• Insertar, seleccionar, actualizar y borrar datos de cualquier tabla
• Puede crear también vistas nuevas
Existe un usuario jefe_londres que puede hacer cualquier cosa con los datos de cualquier tabla
donde la ciudad sea Londres. Puede conectarse desde cualquier sitio.
Existe un usuario usu_continental que puede insertar y seleccionar datos en tablas donde la ciudad
sea Atenas o Paris. Puede conectarse desde cualquier sitio.
Existe un usuario pruebas que puede hacer consultas a cualquier tabla. Solo puede hacerlo el que
tenga cierta IP (la del compañero de al lado)
Solución:
6.6. Vistas 83
Bases de datos, Versión 1.1
Para el segundo apartado hay que permitir a ‘jefe_londres’ que manipule las tablas donde la ciudad sea
Londres. Las tablas que cumplen este requisito son proveedores, partes y proyectos.
Este requisito obliga a crear tres vistas separadas para cada una de las tres tablas.
create view partes_londres as
select * from partes
where ciudad=’Londres’;
grant insert,select on
proyectos.proyectos_continentales,
proyectos.partes_continentales,
proyectos.proveedores.continentales
to
’jefe_continental’@’ %’;
84 Capítulo 6. Administración
Bases de datos, Versión 1.1
identified by ’prueba’;
Con esto el servidor de bases de datos arranca, ignorará todas las claves y permisos y se quedará en
segundo plano.
2. En otra consola, volvemos a conectar con mysql, pero ahora no hará falta poner clave a root.
mysql -u root
mysql> use mysql;
mysql> select user,host,password from user;
mysql> update user set password=PASSWORD("1234")
where user=’root’ and host=’localhost’;
3. Una vez hecho el update, podemos parar el proceso mysqld y volver a arrancarlo normalmente
disponiendo de la clave de root recuperada.
6.8.1 Introducción
Las copias de seguridad permiten a un administrador recuperar los datos en casos de desastre informáti-
co. En líneas generales cualquier desastre conllevará cierta pérdida de datos.
Existen diversos tipos de copia de seguridad:
Físicas: copiar los directorios de la base de datos. La ventaja es que es muy fácil de hacer. El
inconveniente es que MySQL no reconoce directorios que no estén gestionados por él.
Lógicas: son copias procesadas y generadas por el propio SGBD. Son un poco más difíciles de
hacer (hay que aprender comandos) pero son muy fáciles de restaurar. Si hay muchos datos en
muchas tablas, las lógicas pueden llegar a ser muy lentas.
Otra posibilidad es distinguir las copias de seguridad que se hacen “en caliente” o “en frío”.
“En frío”: el servidor SE PARA y nadie puede registrar datos nuevos o borrar datos viejos.
“En caliente”: el servidor no se para, aún a riesgo de que haya datos que no entren en esta copia
de seguridad y se queden para la siguiente.
El comando mysqldump es el más utilizado para hacer copias de seguridad lógicas en caliente. Este
comando se conectará al servidor de bases de datos y volcará los datos que pidamos a un fichero SQL.
Las opciones que maneja el programa son las siguientes
–single-transaction: con este parámetro hacemos que nuestra copia se procese como un único gran
conjunto de operaciones de lectura de datos. Esto permite asegurar que no hay solapamientos en
operaciones de cambios en los valores de los datos.
-u root -p: No siempre hace falta ser el administrador. Si existe un usuario
‘dam1’@‘10.9.0.0/255.255.0.0‘ y dicho usuario tiene permisos de lectura en una base de
datos también los tendrá para hacer la copia de seguridad.
mysqldump -u root -p --single-transaction proyectos > copia1.sql
Es posible hacer copias de seguridad solo de ciertas tablas. Esto permite ahorrar tiempo en la copia y
además perturbar menos la carga de trabajo del SGBD.
Si por ejemplo, deseásemos copiar solo la tabla partes, basta con indicar su nombre detrás del nombre
de la base de datos
mysqldump -u root -p --single-transaction proyectos partes > copia2.sql
Los outfiles son archivos donde se pueden dejar los resultados de consultas. Proporcionan mucha versa-
tilidad y flexibilidad, pero se deben tener los permisos correspondientes por parte del administrador del
sistema operativo.
Por ejemplo, para hacer una copia de seguridad de los proveedores de Londres haríamos esto
mysql -u root -p
mysql> use proyectos;
mysql> select * into outfile ’prov_londres.txt"
from proveedores where ciudad=’Londres’;
Se podría poner una ruta como ‘C:prov_londres.txt’. Si no lo ponemos el archivo se crear en mysqldat-
aproyectos
Supongamos que se pierden los datos de los proveedores de Londres
mysql> delete from proveedores where ciudad=’Londres’;
86 Capítulo 6. Administración
Bases de datos, Versión 1.1
Las copias de seguridad completas son muy fáciles de restaurar. Sin embargo, si una BD es grande será
muy lenta de hacer, interrumpirá el trabajo del SGBD y el espacio en disco se agotará rápidamente.
Las copias de seguridad incrementales permiten almacenar solamente los cambios hechos desde un
cierto momento. Por ejemplo, se podría hacer una copia completa el día 1 de cada mes y luego al final
de cada día, una incremental.
Si hubiera un fallo, por ejemplo, el día 17, se necesitarán aplicar las copias en orden empezando por la
completa seguida de los 16 incrementos. Esto significa que la restauración de copias incrementales es
más pesada de hacer que las completas.
Para poder hacer copias incrementales, MySQL debe haber sido arrancado con la opción correcta.
mysqld --log-bin
mysql -u root -p
mysql> update...
#Esto obliga a volcar los nuevos logs que
#se hayan podido generar
mysqladmin -u root -p flush-logs
Usando los comandos mysqlbinlog podemos volcar cualquier archivo de log en un fichero mysql.
88 Capítulo 6. Administración
CAPÍTULO 7
Access
7.1 Introducción
7.2 El entorno
Al arrancar Access se ofrecen un conjunto de plantillas que contienen BD “prefabricadas” con tablas
ya creadas junto con las claves y las relaciones entre dichas tablas. Esto permite acelerar el tiempo de
desarrollo en ciertos casos, sin embargo en otros se deberá asumir el control y crear las tablas, claves y
relaciones desde cero.
Al crear una base de datos en blanco, Access ofrece un diseño inicial de la tabla en la que ya hay un
campo llamado “Id” de tipo “autonumérico”.
Un tipo autonumérico es un número que se incremente en uno de forma automática.
Se pueden quitar y poner columnas desde este entorno inicial así como indicar los tipos de los datos de
forma sencilla. Se pueden marcar varios campos como “único”, es decir sus valores no se pueden repetir.
Si un campo tiene la marca “se requiere” es que es obligatorio rellenarlo con algo.
Cuando un número se manipula para que muestre más o menos decimales no se va a modificar el número
almacenado.
Access permite indicar que una columna se va a utilizar a menudo para hacer búsquedas. Si algunos
valores se usan mucho la inserción será más cómoda.
El botón “Relaciones” permite establecer relaciones de clave ajena entre las tablas de una base de datos.
89
Bases de datos, Versión 1.1
7.2.1 Ejercicio
90 Capítulo 7. Access
CAPÍTULO 8
8.1 Introducción
Un objeto es una representación de una entidad física que consta de atributos y métodos.
La herencia es la capacidad de compartir automáticamente atributos y/o métodos.
En BBDD una relación es lo mismo que una tabla. El nombre “relación” proviene del concepto
matemático de relación.
Las bases de datos objeto-relacionales son aquellas capaces de manipular relaciones utilizando concep-
tos relacionados con la programación orientada a objetos.
Aparte de todo esto, las bases de datos objeto-relacionales suelen tener otras capacidades interesantes,
como la manipulación de datos espaciales, textuales e incluso representaciones en XML.
XML es un formato de intercambio de datos basado en marcas.
En este tema veremos como utilizar PostgreSQL, que es un sistema de BBDD objeto-relacional que
ofrece las capacidades que hemos comentado.
Durante la instalación de Postgres podremos elegir los directorios de instalación del programa y de datos.
Se puede obtener una pequeña mejora en la eficiencia almacenando los datos en un disco duro distinto.
Por otro lado, en la instalación se nos pedirá la clave de administración del usuario principal (llamado
postgres).
Las máquinas virtuales tienen diversos modos de funcionamiento que condicionan lo que tenemos que
hacer para que alguien pueda acceder a nuestro Postgres (o MySQL) dentro de Virtual BOX
NAT: El anfitrión actúa de “router”
Red Interna: la comunicación solo se da entre VM
91
Bases de datos, Versión 1.1
Como la máquina virtual es una más de la red, bastará con configurar el SO virtualizado para que alguien
pueda acceder a la IP del SO virtualizado y conectar con el puerto 5432 que es el de Postgres.
Este modo ofrece una mayor seguridad, ya que VirtualBox actúa como un router con su propio cortafue-
gos.
Para configurar el acceso a Postgres dentro de VirtualBox hay que configurar correctamente el envío de
puertos.
El objetivo final es que cuando alguien conecte con la IP de nuestro SO virtualizado, VirtualBox autorice
esa entrada de tráfico. El proceso es el mismo que se conoce como “abrir puertos”.
Se debe autorizar el tráfico para el puerto TCP 5432 y reenviarlo a la IP del SO virtualizado sin poner
nada en la IP del SO anfitrión (lo que indica que nos da igual la IP de origen que inicia la conexión).
En este caso, se debe configurar el SO anfitrión para que reenvíe el tráfico hacia el SO virtualizado. Es
decir, el SO anfitrión debe tener capacidades de enrutamiento.
No funcionará si alguien se conecta desde otra máquina física distinta. El modo red interna es para hacer
experimentos y el tráfico generado nunca sale de la máquina.
El funcionamiento es muy similar a MySQL. Hay un programa servidor que espera peticiones y nos
conectamos a él con un programa cliente.
Un cliente puede ser gráfico o textual. En cualquiera de los dos casos, las operaciones que se pueden
hacer son las mismas.
Al usar el interfaz gráfico podemos hacer distintas operaciones de creación con el botón derecho del
ratón mientras que en el interfaz textual deberemos lanzar comandos.
Postgres respeta el estándar ANSI SQL, al igual que MySQL, por lo que los comandos son iguales.
Ejemplo:
CREATE TABLE partes
(
id integer primary key,
nombre varchar(20),
color varchar(8),
peso numeric(3,1),
ciudad varchar(15)
);
Se pueden poner también claves ajenas, de la misma forma que se podía en MySQL.
CREATE TABLE propietarios
(
id integer primary key,
nombre varchar(20),
id_parte integer,
foreign key (id_parte)
references partes(id)
);
Al tener las tablas vacías, si intentásemos insertar este valor, veremos que no se puede. Si el propietario
con el código 3, llamado Juan posee la parte 1, deberíamos escribir lo siguiente:
INSERT INTO propietarios VALUES (3, ’Juan’, 1 );
Para que esto funcione, primero deberíamos hacer algo como esto
INSERT INTO partes VALUES (1,’Tornillo’, ’Rojo’, 12.3, ’Londres’ );
Para ver las tablas que hay se puede usar el pseudocomando d. Para ver la descripción de una tabla
concreta se puede usar d <nombre_de_tabla>
Herencia
La herencia permite que una tabla herede automáticamente los campos y restricciones de otra tabla a la
que se llama tabla padre.
Por ejemplo, supongamos que en una empresa hay empleados con id y sueldo, pero despues hay varios
tipos de empleado, como investigador, becario y administrativo.
Creación de la tabla padre:
CREATE TABLE empleados
(
id integer primary key,
nombre varchar(50),
sueldo numeric(6,2)
);
Ejercicio: insertar el investigador con id 5, con nombre ‘Tomas’, sueldo 3500 y nombre_proyecto ‘Con-
sola’.
Respuesta: El código SQL es el siguiente:
INSERT INTO investigadores VALUES (5,’Tomas’, 3500, ’Consola’);
Si ahora consultamos las dos tablas veremos que el valor SE INSERTA EN LAS DOS TABLAS
Podemos repetir la inserción de valores, las veces que deseemos, y siempre se propagarán los valores
INSERT INTO investigadores VALUES ( 7,’Julian’, 5100, ’Antena’ );
Ejercicio: Construir las tablas Becarios y Administrativos que heredan de Empleados. La tabla Becarios
tiene los campos duracion_contrato (integer) y la Administrativos tiene los campos categoria varchar(10)
y titulacion varchar(15). Insertar valores en las dos tablas.
CREATE TABLE becarios ( duracion_contrato integer )
inherits (empleados);
Ejercicio: Borrar el empleado cuyo código es el número 7. Examinar las tablas investigadores y emplea-
dos para ver qué ha ocurrido.
delete from empleados
where id=7;
Ejercicio: Borrar el investigador cuyo código es el número 42. Examinar las tablas investigadores y
empleados para ver qué ha ocurrido.
Ejercicio: La empresa en la que trabajamos ha decidido crear dos categorías adicionales de empleados.
Los becarios repartidores y los becarios auxiliares.
La tabla Repartidores tiene un solo campo llamado km y que es de tipo numeric (6,1). La tabla aux-
iliares tiene dos campos denominados horas_extra, de tipo integer, y el campo tipo_acceso, que es un
varchar(30).
Insertar valores en Repartidores y Auxiliares y comprobar qué ocurre en las diversas tablas.
CREATE TABLE repartidores
(
km numeric(6,1)
) INHERITS (becarios);
Un repartidor tiene un id (22), un nombre (Ramon), un sueldo (870), una duración de contrato (6 meses),
y un kilometraje 1450.
INSERT INTO repartidores VALUES
(
22, ’Ramon’, 870, 6, 1450
);
Un auxiliar tiene un id (33), un nombre (Ricardo), un sueldo (760),una duración de contrato (18 meses),
unas horas extra (85), y un tipo de acceso (Convenio)
INSERT INTO auxiliares VALUES
(
33, ’Ricardo’, 760, 18,
85, ’Convenio’
);
Conclusión: la herencia funciona como un árbol de tablas, en las cuales el SGBD propaga correctamente
todos los datos hacia las tablas padre. Además, al construir las tablas no es necesario construir ninguna
clave ajena ni especificar borrados o actualizaciones en cascada.
Tipos de herencia
5, ’Alicia’, 1950
);
Cuando en una tabla hay datos suyos y datos de otras tablas que heredan, la selección de datos puede
requerir comandos especiales.
¿Cómo se pueden recuperar simplemente las personas que son empleados normales, sin tener en cuenta
becarios o investigadores?.
Para recuperar tales datos se debe hacer lo siguiente
select * from only empleados;
En resumen: si se desea recuperar los datos de una tabla sin incluir los datos de sus posibles tablas hija,
se debe hacer un select * from only <nombre_de_la_tabla>
Los lenguajes de programación ofrecen soporte para crear nuestros propios tipos de datos (en Java, se
llaman “clases”). PostgreSQL ofrece soporte para crear nuestros propios tipos o clases.
Una vez creado un tipo, podemos crear tablas cuyos campos sean del tipo que hemos creado.
Para crear un tipo de datos, se debe hacer lo siguiente
CREATE TYPE Rectangulo AS
(
la_base int,
altura int
);
Y para usar ese tipo en un campo, se usa de la misma forma que cualquier otro tipo.
CREATE TABLE rectangulos
(
id int primary key,
r Rectangulo
);
¿Como se insertan datos en estas tablas?. La inserción de tipos creados por nosotros requiere usar ‘(
<datos> )’.
INSERT INTO rectangulos VALUES
(
1, ’(2, 12)’
);
Ejercicio: crear una tabla que pueda almacenar el tipo de datos Punto3D. Un punto en 3D tiene tres
coordenadas x, y, z que pueden ser números con hasta 2 decimales. Insertar algunos valores en la tabla.
CREATE TYPE Punto3D AS
(
x decimal(8,2),
y decimal(8,2),
z decimal(8,2)
);
Un detalle importante es que cuando los valores sean cadenas NO SE DEBEN DEJAR ESPACIOS
ENTRE LAS COMAS.
Ejercicio: crear un tipo de datos Linea que tenga un campo m (que es la pendiente de la recta) de tipo
decimal(8,2), un campo k que es la constante a sumar, de tipo decimal(8,2) y un campo orientacion que
es varchar(5). Crear una tabla que permita almacenar valores e insertar 3.
CREATE TYPE Linea AS
(
m decimal(8,2),
k decimal(8,2),
orientacion varchar(5)
);
Cuidado: al insertar información de los varchar, se deben evitar los espacios entre comas.
INSERT INTO lineas VALUES
(
1, ’(3,2,N-S)’
);
select to_tsvector(
’Postgresql es un
sistema gestor de base de datos’)
@@
to_tsquery (’mysql & postgresql’);
select to_tsvector(
’Postgresql es un
sistema gestor de base de datos’)
@@
to_tsquery (’mysql | postgresql’);
to_tsquery(’virtual’);
Si indicamos el idioma del texto, Postgres utilizará una base de datos interna para eliminar las stop-words
adecuadas para ese idioma.
¿Qué ocurre si una misma palabra buscada aparece en dos o más documentos?.
Distintos usuarios pueden haber utilizado distintos sistemas de referencia. Si se proporciona al GIS las
diferencias entre los dos puntos (0,0) el GIS puede calcular automáticamente los movimiento entre dos
mapas que hayan usado distintos Sistemas de Referencia.
En un SIG tenemos tres elementos principales para almacenar información geográfica
Puntos
Líneas
Polígonos
Para crear una base de datos, podemos hacer lo siguiente desde la línea de comandos o desde el pgAdmin.
Esto indica que queremos que nuestra BD actúe como una extensión PostGIS, es decir como una base
de datos SIG
create extension postgis;
(
’LINESTRING(4 1, 4 4,5 7)’
)
);
Ejercicio: Utilizando la función ST_Intersects averiguar qué parcelas tienen intersecciones con otras
parcelas.
select p1.id, p2.id
from parcelas as p1,
parcelas as p2
where ST_Intersects
(
p1.parcela, p2.parcela
)=’t’ and p1.id<>p2.id;
Se puede calcular el area de un polígono cualquiera por irregular que sea o independientemente de los
huecos son ST_Area
select id, ST_Area(parcela) from parcelas;
Índices y tablas
genindex
modindex
search
103