Práticas de Bases de Datos

Anuncio
Práticas de
Bases de Datos
o
2 de Sistemas
Juan David González Cobas
Fernando Cano Espinosa
Curso 2010-2011
1. TOMA DE CONTACTO
1. Virtualización. Para el desarrollo de las prácticas de Bases de Datos vamos a utilizar un
gestor llamado Postgres. Lo haremos sobre Ubuntu, una distribución de linux, que correrá como una máquina virtual. El software de virtualización es VirtualBox, recientemente
adquirido por Oracle. Por tanto, para comenzar las prácticas, desde Windows y con vuestra
cuenta autenticada por Ident, ejecutáis VirtualBox y arrancáis la máquina virtual denominada Bases de Datos. Una vez hecho esto se os comunicará el nombre de usuario y clave, para
poder empezar a utilizar Ubuntu.
2. Qué es postgreSQL. De forma sencilla diremos que postgreSQL es un gestor de bases de
datos. Es una ’aplicación’ que nos permite entre otras muchas cosas definir y manipular
bases de datos. Se trata de sofware libre que corre sobre Linux-Unix aunque exixten versiones para otros sistemas operativos. Como gestor es posiblemente uno de los que incluye
un SQL (lenguaje con el que realizaremos nuestras operaciones) más estándar. Para manejar postgreSQL disponemos, entre otras muchas opciones, de un intérprete de comandos (un
terminal-based front-end), el psql, con el que podremos trabajar en modo texto. Existen otras
aplicaciones en modo gráfico como pgadmin3 que podremos utilizar en alguna ocasión. También es posible trabajar con prostgreSQL a través de la web con php. Nosotros vamos a trabajar con la más sencilla. Dependiendo del ordenador que nos ha tocado es posible que no
dispongamos de un servidor postgres bien configurado. Para ello será necesario seguir las
instrucciones del documento configuracion_postgres.pdf que se encontrará en la página web
de las prácticas.
3. Ejecutar psql. Para empezar cada alumno debería tener su propia cuenta en Linux. Una vez
iniciada la sesión abrimos un terminal y vamos a ejecutar la siguiente secuencia de comandos. Ejecutamos el psql de la forma
$ psql -U username base_de_datos
NOTA: en lo que sigue vamos a utilizar como username un usuario de la base de datos que
debe estar creado en cada máquina y que tiene como nombre ’alumno’ y de password ’alumna’. En el caso del parámetro base_de_datos, se trata de una base de datos que ya exista. En
una instalación normal de prostgreSQL existe una base de datos de nombre template1 a la que
siempre es posible conectarnos. Por lo tanto nuestra orden será:
$ psql -U alumno template1
Una vez en el intérprete veremos el prompt
template1=>
que nos indica que la base de datos a la que estamos conectados es template1. Se trata de
una base de datos patrón que no vamos a utilizar. El símbolo >significa que no somos superusuarios de postgreSQL, en otro caso se nos mostrará el símbolo #.
4. Un rápido ejemplo. Ahora, sin salir del psql vamos a crear nuestra propia base de datos
mediante la orden
template1=> create database miprueba;
No olvidar el ’;’ para finalizar la orden. Ya tenemos creada nuestra base de datos con nuestro
nombre de usuario. Si lo que queremos ahora es conectarnos a ella debemos ejecutar
template1=> \c miprueba;
En este momento el prompt debe indicar el nombre de nuestra base de datos, que se encuentra vacía. Vamos a crear una tabla t1 con dos columnas id , nombre una de tipo entero y otra
de tipo cadena. Ejecutaremos
miprueba=> create table t1 (id int, nombre varchar(10));
1
Como la tabla está vacía vamos a insertar un par de filas:
miprueba=> insert into t1 values (1, ’Ana’);
miprueba=> insert into t1 values (2, ’Luis’);
Comprobamos que el contenido de la tabla es el que esperamos.
miprueba=> select id, nombre from t1;
Ante un imprevisto cambio de sexo vamos a modificar nuestros datos de la forma:
miprueba=> update t1 set nombre=’Luisa’ where id=2;
Ahora, ahítos de alegría, volvemos a dejar las cosas como al principio y salimos ejecutando
la secuencia de órdenes:
miprueba=> delete from t1;
miprueba=> drop table t1;
miprueba=> \c template1
template1=> drop database miprueba;
template1=> \q
5. El entorno de trabajo. El intérprete de comandos psql puede parecer un poco incómodo para
aquellos que no estén acostumbrados a trabajar con este tipo de entornos, por ello vamos a
ver un par de detalles para agilizar nuestro trabajo. Como muchas órdenes pueden ocupar
más que una línea, es normal hacer uso de un editor. Podemos definir el editor que preferimos (kwrite, kate, vi, emacs, gedit, joe, pico, etc.), para ello desde la línea de comandos de
Linux, ejecutaremos la orden
$ export PSQL_EDITOR=mieditor_preferido
Si entramos de nuevo en el intérprete psql, nos daremos cuenta que con las flechas del cursor
podemos recuperar las órdenes que dimos anteriormente; psql guarda un histórico de nuestras órdenes por lo que fácimente podemos volver a crear nuesta base de datos miprueba.
Podemos optar por no usar un editor y trabajar con múltiples lineas de tal forma que mientras que no finalicemos la orden, el intérprete nos presentará un prompt diferente en la sucesivas líneas. Por ejemplo si queremos insertar un cliente nuevo, haríamos
miprueba=> insert
miprueba-> into t1
miprueba-> values (3,
miprueba(> ’Pedrito
miprueba’> ’
miprueba(> )
miprueba-> ;
Observar que el prompt va cambiando dependiendo del estado en que que nos encontremos
( =>, ->, ’>) y que la orden se finaliza con el ’;’.
Cada orden se guarda en un buffer, que se llama el ’query buffer’. Si invocamos al editor nos
permitirá modificar la última orden. Para hacer esto tan sólo tendremos que ejecutar \edit o
sencillamente \e. Al salir del editor el intérprete ejecutará lo que hemos escrito. Invocar al
editor y veréis el insert anterior, y podéis insertar otro cliente.
Otra alternativa, posiblemente más cómoda, sobre todo si lo que queremos es ejecutar un
fichero entero de órdenes, consiste en mantener un editor abierto en una ventana, y en otra
ventana, tener el intérprete de psql. Supongamos que el fichero que editamos se corresponde
con /home/pepe/bdatos/miFicheroDeOrdenes.sql; nos colocamos en el directorio /home/pepe/bdatos,
(en psql, con la orden
cd , nos podemos cambiar al directorio que especifiquemos); y para ejecutar el fichero bastaría
poner en el prompt
miprueba=>\i miFicheroDeOrdenes.sql
2
6. Crear la base de datos. En el directorio de prácticas de la asignatura existen varios ficheros
que deberíais copiar en un directorio vuestro. Estos son:
createPedidos.sql: es un scrpit sql que contiene las órdenes de creación de la base de
datos y las tablas.
insertPedidos.sql: es un scrpit sql que inserta valores en las tablas.
Pedidos.pdf y pedidos_uml.pdf: enunciado, diagrama Entidad Relación y tablas resultantes de la base de datos de pedidos
Una vez hecho desde el psql ejecutar las órdenes:
template1=> \i createpedidos.sql
pedidos=> \i insertpedidos.sql
En este momento deberíais tener creada la base de datos e insertados los datos en las tablas
y por tanto listos para empezar a realizar consultas.
7. Los metadatos. Ahora vamos a ver algunas órdenes para ir manejándonos.
template1=> \l - muestra las base de datos
template1=> \dt - muestra las tablas de la actual base de datos
template1=> \d tabla - muestra información de la tabla
template1=> \du - muestra las usuarios
template1=> \e - edita el query-buffer
template1=> \i - ejecuta un fichero
template1=> \o - redirecciona la salida
template1=> \h - muestra la ayuda SQL
Ejecutar algunas de estas órdenes. Aún así se recomienda tener a mano, ya sea en papel o en
pantalla, los nombres de las tablas y de las columnas.
8. Practicamos. Vamos a conectarnos a la base de datos de pedidos y a ejecutar varias órdenes
sencillas sobre la tabla de clientes desde el psql. Para ello se puede editar la orden en la
propia línea de comandos o utilizando el editor elegido.
a) mostrar toda la tabla
select *
from clientes;
b) mostrar el id_cliente y el nombre de todos los clientes
select id_cliente,nombre
from clientes;
c) mostrar toda la información de los clientes de Gijón (ojo con las mayúsculas y minúsculas)
select *
from clientes
where ciudad= ’GIJON’;
d) mostar el id_cliente y el nombre de todos los clientes que sean de Gijón o de Mieres
select id_cliente, nombre
from clientes
where ciudad= ’GIJON’ or ciudad = ’MIERES’;
9. Borrar la base de datos y volver al mismo punto en el que estábamos. Teniendo los scripts de
creación e inserción de datos es fácil reconstruir nuestra base de datos de forma rápida.
3
10. Vamos a utilizar la ayuda y ver algunos ejemplos de cómo se expresa la sintaxis de órdenes
SQL. Para mostrar la ayuda de postgreSQL abrimos con un navegador el fichero
file:///usr/share/doc/postgresql-doc-8.4/html/index.html
La sintaxis de las órdenes SQL se encuentra descrita en la P art V I de la documentación.
También podemos llegar a ella directamente abriendo el fichero:
file:///usr/share/doc/postgresql-doc-8.4/html/reference.html
Es posible, no hayamos instalado la documentación, y que no encontremos estos ficheros.
Para instalar la documentación bastaría con ejecutar:
$ sudo apt-get install postgresql-doc-8.4
pero siempre nos quedará París o la página oficial
http://www.postgresql.org
Es muy importante familiarizarse con esta notación, ya no solo para aprender SQL. Se trata,
más o menos, de una gramática libre de contexto, y lo que se nos muestra son las reglas de
producción. En esta notación tenemos que recordar que:
Los símbolos terminales (palabras que aparecen tal cual en las órdenes) se expresan en
mayúsculas( ej. SELECT ).
Los símbolos no terminales (símbolos que producen cadenas de otros símbolos) se expresan en minúsculas (ej. condition, expression)
Las barras verticales expresan distintas alternativas.
Los corchetes expresan que lo que hay dentro es opcional.
Las llaves expresan alguna de las alternativas que se incluyen debe aparecer.
Los puntos suspensivos se utilizan para describir una repetición, generalmente separados por comas, del símbolo que se encuentra a la izquierda de los puntos suspensivos.
Al aparecer entre corchetes se describe una lista de uno a más elementos.
Para cada orden encontraremos generalmente con los siguientes apartados
El nombre de la orden.
La sintaxis de la orden (synopsis).
Una descripción.
Una explicación de los parámetros.
Unas notas.
Unos ejemplos.
La compatibilidad con otras versiones de SQL.
Algunos aspectos de la sintaxis no son fáciles de encontrar en esta documentación, pero
dado que se trata de un SQL bastante estándar cualquier sintaxis nos puede servir para crear
consultas sencillas. Aún así es recomendable echar un vistazo al Chapter 7. Queries donde
podemos ir desmenuzando la sintaxis del select.
4
11. Seguimos probando algunas órdenes sencillas:
Mostrar (SELECT ) los productos cuyo precio esté entre 90 y 120. Disponemos del predicado between para ello.
select *
from productos
where precio between 90 and 120;
Insertamos (IN SERT ) un nuevo producto
insert into productos (id_producto, nombre, precio)
values (7,’KIWI’, 100);
Observar que no hemos introducido un valor para existencias. Para ello hemos escrito
los nombres (y el orden) de las columnas que vamos a introducir. También podríamos
haber utilizado la palabra reservada null para dicha columna.
Actualizamos (U P DAT E) las existencias del nuevo producto e incrementamos el precio
en un 10 %
update productos
set existencias= 50, precio = precio * 1.1
where id_producto=7;
Borramos (DELET E) el nuevo producto
delete from productos
where id_producto=7;
5
2. EL SELECT COMO UNA FORMA DE VIDA
1. Nos conectamos a nuestra base de datos de pedidos (crearla si fuera necesario)
2. Es fundamental ver y entender bien el significado del Producto (join) de tablas. Cuando
queremos recuperar información que se encuentra repartida entre distintas tablas vamos a
basarnos en dos ideas: la primera es la de repetir columnas en diferentes tablas para poder
enlazar dicha información y la segunda es utilizar la operación producto cartesiano de conjunto (entendiendo que una tabla en un conjunto de filas).
Para realizar el producto cartesiano (cross join) de pedidos con clientes podemos expresarlo así:
select *
from pedidos , clientes;
o de forma algo más elegante así:
select *
from pedidos cross join clientes;
Para ver más claramente lo que hace esta consulta vamos a mostrar las columnas pedidos.id_cliente
y clientes.id_cliente
select
pedidos.id_cliente,
clientes.id_cliente
from pedidos cross join clientes;
Añadimos al from la tabla de empleados y mostramos también pedidos.id_empleado y
empleados.id_empleado. Observamos cuántas filas obtenemos. Y nos damos cuenta que
equivale al producto de los cardinales de los tres conjuntos de filas (tablas).
Estudiar sobre la anterior consulta
select *
from pedidos cross join clientes;
qué condición que debe imponerse a las filas en la cláusula W HERE para obtener un
resultado coherente.
Modificar esta consulta de forma que no sea necesario imponer la condición en el W HERE.
Para ello podemos realizar el producto natural (N AT U RAL JOIN ). O también el IN N ER
JOIN que como veremos presenta dos alternativas, una con utilizando la cláusula ON
y otra con la cláusula U SIN G.
3. Obtener el id_pedido, el nombre del cliente para todos los pedidos.
4. Obtener el id_pedido, el nombre del cliente y el nombre del empleado para los pedidos atendidos por empleados de Mieres.
5. Obtener el id_pedido, el nombre del cliente y el nombre del empleado para los pedidos realizados el 2 de septiembre de 2006 que han sido atendidos por empleados de Mieres.
6. Introducir las variables de tupla (con el primer objetivo de ahorrarse escribir mucho).
7. Ver cómo se renombran las columnas para distinguir entre el nombre del cliente y del empleado.
8. Obtener el id_pedido, el nombre del cliente, el nombre de los productos y cantidad de los
mismos para todos los pedidos.
9. Nombre del cliente y nombre del empleados que comparten ciudad
10. Parejas de nombres de clientes que comparten ciudad
6
3. EL SELECT Y SUS AMIGOS
1. Comparaciones de cadenas (Pattern Matching, LIKE). Para comparar cadenas tenemos el
operador LIKE que podemos utilizar en combinación con los caracteres ’ %’ y ’_’ que tienen,
respectivamente, el mismo significado que el ’*’ y ’?’ en linux y otros sistemas operativos.
Mostrar el identificador y nombre de aquellos productos que cumplen lo siguiente:
• empiezan por ’P’
• terminan en ’AS’
• contienen las subcadena ’TA’
En postgreSQL podemos utilizar el ILIKE para que no se distingan mayúsculas de minúsculas (case insensitive).
2. El operador IN (NOT IN )
Mostrar el identificador y nombre de aquellos productos pedidos por ’PEPE’
Mostrar el identificador y nombre de aquellos productos NO pedidos por ’PEPE’
En muchos casos el IN permite hacer intersecciones de conjuntos y el N OT IN nos sirve
para la diferencia de conjuntos.
3. Otras comparaciones
Mostrar el identificador y nombre de aquellos productos que cuestan más que alguno
de los que ha pedido ’PEPE’
4. El predicado EXISTS
Mostrar pedidos con su fecha en los que no aparece ningún producto.
5. La UNION
Mostrar los nombres de empleados o clientes que viven en MIERES
Añadimos la calle
6. La INTERSECCIÓN (INTERSECT)
Mostrar aquellas ciudades donde viven tanto empleados como clientes.
7. El MINUS (EXCEPT)
Mostrar aquellas ciudades donde viven empleados pero no clientes.
7
8. El inexistente CON T AIN S
El CON T AIN S sirve para implementar la inclusión de conjuntos (⊆), a diferencia del IN (∈)
que nos permite comprobar si un elemento pertenece a un conjunto. Por tanto los parámetros
de CON T AIN S son dos conjuntos (el resultado de dos select’s). Se suele utilizar en consultas del tipo ’Para todo’.
Mostrar los clientes que han pedido todos los productos que ha pedido ’PEPE’. Vamos
a definirnos dos conjuntos: A y B.
Conjunto A: productos pedidos por cada cliente (c1 ).
Conjunto B: productos pedidos por clientes cuyo nombre es PEPE.
Si se cumple que B ⊆ A entonces el cliente c1 deber ser mostrado.
select nombre
from clientes c1
where
( select id_producto -- Conjunto A: productos pedidos por c1
from pedidos p inner join detalles_pedido dp using (id_pedido)
where p.id_cliente = c1.id_cliente)
contains
( select id_producto -- Conjunto B: productos pedidos por PEPE
from clientes c2 inner join pedidos p using (id_cliente)
inner join detalles_pedido dp using(id_pedido)
where c2.nombre ilike ’PEPE’);
Si se observa el predicado contains devuelve TRUE si el conjunto A contiene al conjunto
B. Lamentablemente SQL no implementa este predicado y tiene que ser simulado con
la condición NOT EXISTS (B MINUS A), es decir NOT EXISTS (B EXCEPT A).
Demostramos nuestra capacidad de aprendizaje: mostrar aquellos productos que aparecen en todos los pedidos
Insistimos: clientes que han sido atendidos por todos los empleados de Gijón.
9. Algo sobre Valores nulos.
Para poder manejar los valores nulos en SQL tenemos que tener en cuenta algunos criterios.
Además SQL nos ofrece algunos operadores que nos facilitan el tratamiento de los valores
null.
En general, las expresiones que incluyen valores nulos devuelven como resultado null.
En las expresiones lógicas se siguen las reglas mostradas en las tablas del epígrafe 9.1.
Logical Operators.
El operador IS (value IS null) nos devuelve true si value contiene el valor null.
La expresión CASE nos permite, entre otras cosas, controlar que si un resultado es null
podemos cambiarle su valor para poder trabajar mejor con él. Por ejemplo, en algunas
expresiones aritméticas es útil convertir valores nulos en ceros (ver 9.12.1).
La función COALESCE() también nos permite algo parecido a lo anterior pero de otra
forma(ver 9.12.2).
La función N U LLIF () es como la función inversa a la anterior (ver 9.12.3).
Mostrar los identificadores de pedido y los del empleado, pero si no tiene un empleado
asociado mostrar un ’0’.
Mostrar los identificadores de pedido y los del empleado, pero si no tiene un empleado
asociado mostrar la cadena ’sin asignar’.
Mostrar los empleados que no han atendido ningún pedido utilizando el operador NOT
IN, ver qué pasa y arreglarlo.
8
10. Empezamos a agrupar (group by, having, count() , max(), etc.)
Mostrar el número de pedidos atendidos por ’MARIA’.
Identificador del empleado y número de pedidos atendidos por él.
Nombre del empleado y número de pedidos atendidos por él.
Fecha y número de empleados que han atendido algún pedido en dicha fecha.
Identificador de Pedido, fecha del mismo, número de de productos diferentes que incluye y la cantidad media de productos por pedido.
Identificador de Pedido y coste total del mismo para aquellos pedidos que incluyen más
de dos productos distintos.
Para aquellos productos cuyas existencias no cubren las cantidades pedidas, obtener
su nombre, sus existencias, las cantidades pedidas y las cantidades necesarias que la
empresa tiene que comprar para poder cubrir todos los pedidos.
11. Ordenamos un poco
Nombres de productos y el número de pedidos en los que aparecen, ordenados por el
nombre alfabéticamente y por el número de pedidos de forma descendente
9
4.
Práctica 4: EL SELECT Y LOS JOINS
Nombre de los empleados con los identificadores de los pedidos atendidos por ellos
Nombre de TODOS los empleados con los identificadores de los pedidos atendidos por
ellos
Productos y el número de pedidos en los que aparecen
Relaciones entre clientes y empleados. Mostrando TODOS los clientes y TODOS los
empleados aunque no haya realizado ningún pedido
10
Descargar