EJERCICIOS SQL (SISTEMAS DISTRIBUIDOS 2013) Estos ejercicios si se hacen antes de la publicación del fichero completo con las respuestas se evalúan como deberes. Por que aprender SQL: SQL es una manera universal de acceso a bases de datos relacionales (todos los BD en el mundo en este momento) y por eso es algo necesario en el uso profesional de ordenadores. Por eso vale la pena de invertir unas horas para aprender la base de SQL. Estos ejercicios se componen de dos partes -- una de problemas y pistas y otra de soluciones. Para ayuda general hay que referirse a www.w3schools.com (la parte SQL) o a las páginas www.firstsql.com/tutor.htm. Es my recomendable leer el material del último enlace. También se pueden utilizar las páginas www.airfareoffice.com/multimedia/edat. En todos los ejercicios hay que conectarse con un servidor SQL y una base de datos. Debido a que hay solo una base de datos para todos, a cada uno se pide que utiliza nombres de los recursos, por ejemplo tablas con nombres que empiezan con su login, por ejemplo si el logins es e999999 las tablas serán e999999_persona o parecidos. Vamos a sustituir esta cadena con e*_ los ejemplos. Como aprender: Con estos 20 ejercicios podéis aprender la ideología de SQL. Los detalles podrán venir practicando. La metodología correcta es: 1. Leer el problema que propone cada ejercicio. 2. Intentar de imaginar que tiene de hacer la máquina de la base de datos para resolverlo. 3. Leer el material de W3School u otro sitio e intentar de resolverlo si no sabemos lo necesario de SQL. Utilizar las palabras claves (en mayúscula azul) para buscar el asunto correspondiente. 4. Intentar de escribir la query. NO COPIAR Y PEGAR EN NINGUN CASO. Podéis gastar unos 2-3 minutos en cada ejercicio intentando. 5. Ver y analizar la respuesta del fichero con respuestas. Si no hemos resuelto el problema, ejecutar la query (NO COPIAR Y PEGAR). 6. Apuntar en un cuaderno la sintaxis de cada sentencia SQL que habéis utilizado. Esto puede servirles como chuleta. Estimación del tiempo -- 3 horas. Por favor, hacer un fichero log de lo que ejecutáis. Esto en mysql se hace con \T <nombre de fichero> Vamos a crear 3 tablas con relaciones y los índices necesarios entre ellas. Una para personas, otra para artículos y tercera para pedidos. Para cada persona guardamos los siguientes datos (el nombre del campo está subrayado): * * * * * id -- un identificador -- un número entero único para cada persona, nombre -- hasta 40 caracteres, apellidos -- hasta 50 caracteres, direccion -- hasta 100 caracteres, el dinero que tiene como credito en esta tienda. Para cada artículo guardamos * id -- identificador del articulo -- número entero único para cada artículo. * nombre de articulo hasta 80 caracteres, * el precio del artículo * cantidad disponible. Para cada pedido vamos a guardar * a que persona corresponde (id_persona), * de que artículo se trata (id_articulo), * qué cantidad del artículo refiere Ejercicio 0: Conectar con el servidor. De casa se recomienda de entrar en el servidor instalando un cliente mysql en su ordenador (existen para linux y windows). PARA ESTOS EJERCICIOS se recomienda NO UTILIZAR interfaz gráfico con el cliente instalado. Alternativamente podéis conectar con ssh al servidor de prácticas y con un browser con la BD que utilizamos. En el servidor se entra con: mysql -h mysql8.websitesource.net -u qetu159_student -p qetu159_pruebas También podeos ver vuestras tablas con interfaz gráfica en el servidor: http://mysql8.websitesource.net/phpMyAdmin/index.php (usuario y contraseña como de arriba) Ejercicio 1: Crear una tabla e*_articulo con la información para los artículos. Los campos para cada artículo deberían de llamarse ID, nombre, precio, cantidad. CREATE TABLE Ejercicio 2: Insertar en la tabla artículo que se llama lapiz, con cantidad 200 y precio de 1,5. INSERT INTO Ejercicio 2.1: Insertar otro artículo: boli, con precio 2 euros y cantidad 300. INSERT INTO Ejercicio 3: Ver los registros que acabamos de insertar. SELECT ... FROM ... Ejercicio 4: Ver la suma de la cantidad de bolis y lápices con una sola query: SELECT agregate_function Se hace con la función sum(expression), donde expression es efectivamente en este caso el nombre del campo. La función SUM es una de las muchas funciones que agregan, es decir a partir de los valores de muchos campos calculan un valor. Ejercicio 4.1: Calcular el total de dinero que tenemos como artículos. SELECT agregate_function Solo hay que introducir una modificación en la query anterior. Ejercicio 5: Cambiar el ID de Lapiz a 1 y el ID de Boli a 2. UPDATE ... SET ID=.... WHERE .... En este caso necesitamos de buscar y cambiar solo el (los) registros que tienen nombre Lapiz y los que tienen nombre Boli. El resultado debería de estar +------+--------+--------+----------+ | ID | nombre | precio | cantidad | +------+--------+--------+----------+ | 1 | Lapiz | 1.5 | 200 | | 2 | Boli | 2 | 300 | +------+--------+--------+----------+ Ejercicio 6: El resultado de una query (SELECT) es muy parecido a una tabla. Crear una tabla e*_articulo_ext con un campo más que vamos a llamar valor, que simplemente es precio*cantidad. Los tipos de los datos no hay que darles expresamente porque estos se derivan de la query. CREATE TABLE ... SELECT .... Ver el resultado: SELECT * from e*articulo_ext; Ejercicio 7. Al no dar nombre explícito a la columna valor, la tabla resulta con nombre de la columna que contiene el carácter * que no es cómodo. Borramos la tabla que hemos creado. DROP TABLE e*_articulo_ext; La operación será denegada -- el usuario alumno no puede quitar tablas (por ejemplo las tablas del vecino :) Ejercicio 8. Crear una nueva tabla llamada e*_art_ext con el nombre correcto de la columna CREATE TABLE ... SELECT ... exp AS alias .... OJO: Tener tablas con columnas que simplemente son funciones de otras columnas es contra productivo. Se da solo como ejemplo de CREATE TABLE. El nombre de la columna no es valor. Para que sea valor tenemos que dar un alias a precio Ejercicio 9. Rellenamos los datos en varias tablas. Crear las tablas e*_person y e*_pedido a partir de las tablas e99_person y e99_pedido. Ver las primeras 10 líneas de cada tabla: SELECT ... LIMIT .... Ejercicio 10. Buscar todos los clientes que se llaman Jose... y tienen apellidos que empiezan con ‘Jimenez’ Se utiliza el operador like: nombre like 'Jose%' El % sirve de la misma forma como * en expresiones regulares de linux (ls Jose*). Ejercicio 11. Encontrar los pedidos correspondientes a las personas que empiezan con Maria y apellido Jimenez… . Imprimir la cantidad de cada artículo que iban a comprar y el identificador del artículo. LEER EL APARTADO DE WHERE EN W3SCHOOL. Apuntar el tiempo que tarda la query. Para esto necesitamos dos tablas -- de pedido y de cliente. Dar alias de pedido a y alias de person b. select ... from ...,... WHERE .... AND b.ID=a.ID_person ....; Ejercicio 12. Encontrar la cantidad del dinero y el nombre el artículo para cada cliente que empieza con 'Maria' y el apellido empieza con ‘Jimenez’. Para esto tenemos que unir tres tablas con la query. Una persona puede ocurrir varias veces para diferentes artículos. Efectivamente vamos a ver que el tiempo de ejecución es muy elevado. Parar la query (ctrl-C) si no podeis esperar. Ejercicio 13. AÑADIR INDICES: Podéis ver que el rendimiento del sistema es muy bajo. Por eso hay que añadir índices a las tablas y relaciones entre las tablas. 13.1. Añadir índices por cada uno de los campos de todas las tablas. CREATE INDEX index_name ON table_name (column_name) Ejecutar la misma query del ejercicio 12. Cuál es el impacto sobre el rendimiento. Ejercicio 14. Añadir restricciones: El identificador de la persona y del artículo debería de estar únicos. Por eso hay que añadir restricción de este campo: Ejercicio 14.1. ALTER TABLE e*_articulo ADD CONSTRAINT uc_article UNIQUE (ID); Ejercicio 14.2. El comando dará errores. Borrar el registro que sobra (son las entradas con número 1 y 2: DELETE FROM e*_articulo WHERE ID=.... AND .....; Ejercicio 14.3. Añadir también la restricción de unicidad del campo ID de la tabla 'person'. Ejercicio 14.4. Añadir otra restricción que es sobre los campos ID_persona y ID_articulo conjuntos en la tabla pedidos. ALTER TABLE e*_pedido ADD CONSTRAINT uc_pedido UNIQUE (ID_...,ID_....); Ejercicio 14.5. Añadir la restricción que el nombre del cliente no puede estar vacio. ALTER TABLE … MODIFY COLUMN columna tipo_de_datos NOT NULL. Ejercicio 14.6. Añadir columna que representa la fecha de nacimiento de la persona y tiene tipo de fecha. ALTER TABLE ... ADD COLUMN ... También añadir un campo observación para cada persona con una capacidad de 2000 caracteres. Ejercicio 15. Ejecutar las queries del punto 12 y medir el tiempo. Ejercicio 16. Efectivamente en la tabla pedido ID_person del pedido refiere una persona y por eso hay que decir que ID_person efectivamente refiere el campo ID de la tabla person. Esto crea una estructura mas eficiente si conectamos las dos tablas en una query. Ejercicio 16.1. Añadir la referencia entre pedido y person. ALTER TABLE ... ADD FOREIGN KEY ... REFERENCES ... Ejercicio 16.2. Añadir la referencia entre artículo y pedido. Ejercicio 16.3. Ejecutar la query del ejercicio 12. ¿Cuál es el rendimiento? Ejercicio 17. GROUP BY Si queremos para cada cliente solo la suma de los artículos que hemos comprado, esto estaría difícil de conseguirlo con lo que hemos hecho hasta al momento. Tenemos que hacer la query que combina los artículos y hacer la suma del articulo.precio*pedido.cantidad pero agrupando los resultados por cliente. Para este propósito se utiliza la construcción GRUOP BY conjunto con una función de agregación (en este caso SUM()). Construir una query que da el importe en pedidos para cada cliente que tiene pedidos. Ejercicio 18. Una lista ordenada por algún criterio se lee mejor. ORDER BY Ejercicio 18.2. Ordenar los resultados de la query del ejercicio 17 por el nombre el cliente. Ejercicio 18.3. Ordenar los resultados de la query por el nombre en orden reverso y solo para los clientes cuyo nombre empieza con 'Jose'. Salir del mysql GUARDANDI EL LOG. Los siguientes dos ejercicios se ejecutan contra la base de datos qetu159_ds y sirven para hacer la práctica. Si les interesan los ficheros fuentes de la tabla Word_text podeis encontrarles en 150.244.59.74/~kostadin/20_newsgroup/<nombre de fichero>. Por ejemplo: http://150.244.59.74/~kostadin/20_newsgroup/sci.space/59848 Ejercicio 19. En la tabla word_text: 19.1 Contar cuantas entradas hay COUNT. 19.2. Contar cuantas palabras se refieren. 19.3. Dar la lista de los ficheros distintos. 19.4. Contar cuantos ficheros distintos hay SELECT DISTINCT 19.5. Contar en cuantos ficheros aparece la palabra 'mars'. 19.5.1. Contar en cuantos ficheros aparece cada palabra. 19.6. Contar cuantas veces aparece la palabra mars en todos los ficheros. 19.7. Contar cuantas palabras hay en cada fichero. 19.8. Contar cuantas palabras promedio hay en cada fichero. Ejercicio 20. Hacer tablas auxiliares para queries frecuentes. Estas tablas habitualmente se hacen temporales (CREATE TEMPORARY TABLE …). Esto está en contradicción con el modelo normalizado de datos, pero si sirve para tener un rendimiento razonable. 20.1. Hacer una tabla e*_word_cnt donde están todas las características para cada palabra que se necesitan para calcular la formula BM25. 20.2. Hacer una tabla e*_file_cnt donde están todas las características para cada fichero que se menciona en la formula BM25. 20.3. Hacer las relaciones entre e*file_cnt y e*word_cnt y e*word_text. 20.3. Hacer una tabla e*_otros para todas las características globales que necesitamos para la formula BM25 (número ficheros, etc.). 20.4. Documentar las queries y hacer un PHP que las ejecuta. 20.5. Utilizar estas queries para calcular BM25 Okapi sobre 4 palabras que buscamos y que el resultado de la formula sea un campo de la query. 20.6. Ordenar los resultados de 20.5 por el valor de la formula. ATENCION: El punto 6 de la práctica 1 se hace más fácil utilizando varias queries y programando en PHP. Si utilizamos tablas hay que utilizar tablas temporales.