práctica Bases de Datos 1 Eva Gómez Ballester Paloma Moreda Pozo Patricio Martínez Barco José Clavel Cerro Ernesto Pérez López Armando Suárez Cueto Dpto. de Lenguajes y Sistemas Informáticos Escuela Politécnica Superior Universidad de Alicante http://www.dlsi.ua.es/asignaturas/bd1/bd1.html índice sesión 0_______________________________________________ 5 select 1 _______________________________________________ 9 BD Proveedores _______________________________________ 13 select 2 ______________________________________________ 21 select 3 ______________________________________________ 27 select fecha___________________________________________ 31 create _______________________________________________ 33 manipulación 1 ________________________________________ 41 manipulación 2 ________________________________________ 47 manipulación 3 ________________________________________ 53 conjuntos ____________________________________________ 59 funciones_____________________________________________ 63 group by _____________________________________________ 67 group by - having ______________________________________ 71 subselect _____________________________________________ 75 subselect - exists ______________________________________ 81 adicionales 1 __________________________________________ 83 adicionales 2 __________________________________________ 85 adicionales 3 __________________________________________ 87 adicionales 4 __________________________________________ 89 adicionales 5 __________________________________________ 91 adicionales 6 __________________________________________ 93 adicionales 7 __________________________________________ 95 sesión 0 ENTORNO ORACLE Objetivos: • Adquirir la destreza mínima para trabajar en el entorno ORACLE iSQLplus. Contenidos • • • • • • • Concepto de Base de Datos y Tabla. Entrar en ORACLE SQL. Manejo de menús. Selección de Base de Datos. Tipos de datos. Ayuda en línea. Salvar y recuperar órdenes SQL. Concepto de Base de Datos y Relación (Tabla) Una base de datos es un conjunto de información interrelacionada que representa un sistema de información particular, y está compuesta por relaciones, o más comúnmente tablas, que almacenan los datos referentes a un objeto o a una interrelación entre objetos. Así, si queremos mantener mediante un gestor de bases de datos información docente, lo que haremos (en este caso en particular) será crear una base de datos que englobe tres tablas: PROFESORES, ASIGNATURAS e IMPARTE. Cada tabla tendrá sus columnas, que representan los correspondientes atributos de la entidad o claves ajenas que permiten relacionar varias tablas entre sí. La BD que gestione esta información se llamará Ejemplo, y las tablas contenidas en ella se presentan en el siguiente cuadro. Base de Datos: Ejemplo PROFESORES ( dni : varchar(10), nombre : varchar(40), categoria : char(4), ingreso : date ) Clave primaria: dni ASIGNATURAS ( codigo : char(5), descripcion : varchar(35), creditos : number(3,1), creditosp : number(3,1) ) Clave primaria: codigo IMPARTE ( dni : varchar2(10), asignatura : char(5) ) Clave primaria: (dni, asignatura) Clave ajena: dni → PROFESORES Clave ajena: asignatura → ASIGNATURAS 5 Extensiones de Ejemplo: ASIGNATURAS codigo descripcion creditos creditosp HI FBD DGBD PC FP 4.5 6.0 6.0 6.0 9.0 HISTORIA DE LA INFORMATICA FUNDAMENTOS DE LAS BASES DE DATOS DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 1.5 3.0 1.5 4.5 IMPARTE PROFESORES dni nombre categoria ingreso dni asignatura 21111222 21222333 21333444 EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO TEU TEU ASO6 21111222 21111222 21333444 FBD DGBD PC 01/10/1993 16/06/1989 16/06/1992 iSQLplus Oracle es un sistema de gestión de bases de datos relacional. Dicho gestor está instalado en un servidor al que se accede por red desde un navegador o un cliente Windows. Desde el navegador, accediendo a la dirección http://oraculo.eps.ua.es:5560/isqlplus, aparece la pantalla de identificación. Para la mayoría de las sesiones, la información a introducir en el formulario es: Usuario: alumno Contraseña: alumno Conexión: oracle Una vez el sistema permite la conexión, disponemos de un área donde introducir órdenes SQL cuyo resultado se obtiene pulsando el botón “Ejecutar”. Podemos probar con la siguiente consulta: select * from profesores resultado: dni 21111222 21222333 21333444 nombre EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO categoria TEU TEU ASO6 Tipos de datos En general, la utilización de varias tablas necesita que ellas se puedan relacionar por una columna común, en este caso dni de profesor, para la relación entre imparte y profesor, y codigo de asignatura, para la relación entre asignatura e imparte. Nótese, sin embargo, que en la tabla imparte el código de asignatura se llama asignatura y en la tabla asignaturas codigo. En realidad, tales atributos son “comunes” porque el dominio es el mismo para ambos y se pueden comparar. Los dominios vienen definidos por los tipos de datos que ofrece el SGBD. Los tipos de datos que acompañan en el esquema de BD a cada columna en cada tabla determinan los valores que pueden tomar éstas. Son de capital importancia a la hora de relacionar tablas en una sentencia select, puesto que sólo podremos comparar columnas con idéntico tipo de datos, o a la hora de manipular datos, dado que, como veremos en próximas sesiones, cada tipo de datos presenta unos requisitos específicos para su manipulación. 6 Algunos de los tipos de datos que nos podemos encontrar en ORACLE son: VARCHAR2(n) Cadena de caracteres de longitud variable con un máximo de n CHAR(n) LONG NUMBER(p,s) RAW(n) LONG RAW DATE (1<=n<=4000) Cadena de caracteres de longitud fija de longitud n (1<=n<=2000) Cadena de caracteres de longitud variable hasta 2 gigabytes, o 231-1 bytes Números con precisión p y escala s (1<=p<=38) (-84<=s<=127) Cadena de caracteres binarios de longitud n (1<=n<=2000) Cadena de caracteres binarios de longitud variable hasta 2 gigabytes Datos de tipo fecha, con la forma dd/mm/yyyy(día, mes y año). Los valores date deben manejarse encerrados entre comillas simples. Rango válido desde 1 de enero de 4712 AC hasta el 31 de diciembre de 4712 DC. INFORMACIÓN ADICIONAL Ayuda en línea. Direcciones con ayuda Oracle disponible: • www.oracle.com • www.redcientifica.com/ En general, es bastante fácil encontrar información en internet por medio de cualquier buscador. Obtener información sobre una tabla de la BD Ejecutar DESC nombreTabla o DESCRIBE nombreTabla para mostrar información de la tabla nombreTabla: ( el nombre de cada columna, si los valores nulos se permiten o no (NULL or NOT NULL) en esa columna, tipo de dato de la columna, por ejemplo, NUMBER, CHAR, VARCHAR2, LONG, DATE, RAW, o LONG RAW, y la precisión de la columna si el tipo de dato lo requiere). Otras informaciones disponibles en el catálogo del sistema (el comando DESCRIBE se basa en algunas de las tablas que se utilizan aquí) son: select distinct table_name, column_name from all_cons_columns where OWNER='BD1TABLAS'; select * from all_cons_columns where OWNER='BD1TABLAS'; select OWNER, TABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE from all_tab_columns where OWNER='BD1TABLAS'; Donde BD1TABLAS es un usuario (el propietario, en este caso, de la BD PROVEEDORES) Para que los datos se muestren en pantalla sin saltos de línea, se puede dar formato a las columnas con las siguientes órdenes, (es permanente para toda la sesión, sólo se ejecutan una vez; si se quiere otro formato, hay que volver a ejecutarlas con las modificaciones oportunas) COLUMN COLUMN COLUMN COLUMN OWNER FORMAT a20 CONSTRAINT_NAME FORMAT A20 TABLE_NAME FORMAT A15 COLUMN_NAME FORMAT A20 7 COLUMN POSITION FORMAT 99 COLUMN DATA_TYPE FORMAT A15 Y también: SET LINESIZE 600 (para evitar que la filas de salida, incluída la cabecera, ocupen , más de una línea) SET PAGESIZE 200 (para evitar cabeceras tantas cabeceras) Sobre guardar órdenes en disco En la máquina se dispone de un disco duro local que se puede utilizar para guardar y recuperar ficheros generados por el alumno. No obstante, no se garantiza que los datos ahí guardados permanezcan de una sesión para otra. Por lo tanto, si se quieren guardar datos con seguridad es preferible hacerlo en un disco removible, o bien utilizando los servicios de disco virtual de la EPS o el Campus Virtual. 8 select 1 SQL - SELECT Objetivos: • Introducir al alumno en el SQL y la orden SELECT. • Comentar el esquema lógico propuesto. Contenidos: • Sistema de información propuesto. • La orden SELECT-FROM-WHERE. • Proyecciones, Selecciones. • Tipos de datos. • ORDER BY Se proporciona información sobre las consultas más sencillas a realizar sobre una BD. LA ORDEN SELECT-FROM-WHERE Sintaxis general de la orden select SELECT [ DISTINCT ] listaColumnas FROM listaTablas [ WHERE condición ] [ GROUP BY listaColumnas [ HAVING condición ] ] [ ORDER BY listaColumnas [ ASC | DESC ] ] Select-From Para realizar consultas sobre una base de datos vamos a utilizar la orden SELECT de SQL. Con la sintaxis que se muestra en el punto anterior seremos capaces de formular cualquier requerimiento (consulta) sobre las tablas que componen una determinada BD. En este momento veremos la expresión mínima de la orden, formada por dos cláusulas, select y from, que obligatoriamente tendremos que especificar en cada consulta que realicemos. Supongamos que sobre la base de datos Ejemplo (cuyo esquema y contenido se presentaron en la sesión anterior) queremos obtener todos los datos acerca de los profesores. Debemos, en primer lugar, seleccionar la base de datos, y ejecutamos (en el Query-language) la siguiente orden select * from profesores resultado: dni 21111222 21222333 21333444 nombre EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO categoria TEU TEU ASO6 9 Al especificar en la lista de atributos un asterisco le indicamos al SGBD que deseamos la información de todas las columnas definidas para la tabla PROFESORES. Si deseamos conocer a qué categorías pertenecen los profesores que se encuentran en la BD: select categoria from profesores resultado: categoria TEU TEU ASO6 Podemos especificar tantas columnas como queramos: select nombre, categoria from profesores nombre resultado: EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO categoria TEU TEU ASO6 Para evitar la salida de filas duplicadas podemos utilizar el modificador DISTINCT: select distinct categoria from profesores resultado: categoria TEU ASO6 Nótese, sin embargo, que las dos órdenes siguientes obtienen el mismo resultado, puesto que la duplicación se refiere a filas completas y no a una columna en particular: select distinct dni, categoria from profesores select dni, categoria from profesores resultado: dni 21111222 21222333 21333444 categoria TEU TEU ASO6 La cláusula WHERE Con la orden select-from obtenemos la información de las columnas requeridas de toda la tabla. Si únicamente queremos información de aquellas filas que cumplen una determinada condición utilizaremos la cláusula where. Pretendemos obtener el nombre de los profesores titulares: select nombre from profesores where categoria = 'TEU' resultado: 10 nombre EVA GOMEZ MANUEL PALOMAR En la construcción de tales condiciones podemos utilizar las conectivas lógicas AND, OR, y NOT, así como los paréntesis para alterar la evaluación de izquierda a derecha. También, los operadores de comparación >, <, >=, <=, <> Nombre de los profesores que son titulares o asociados a 6 horas: select nombre from profesores where categoria = 'TEU' or categoria = 'ASO6' nombre resultado: EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO La cláusula ORDER BY Podemos ordenar la salida producida por nuestra orden select por valores ascendentes o descendentes de una columna en particular. Nombre de las asignaturas ordenadas de menor a mayor número de créditos: select creditos, descripcion from asignaturas order by creditos resultado: creditos 4.5 6 6 6 9 descripcion Historia de la Informática Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente Fundamentos de la Programación Si no se indica nada la ordenación será ascendente. El mismo requerimiento anterior pero en orden descendente y de aquellas que tienen más de 4.5 créditos: select creditos, descripcion from asignaturas where creditos > 4.5 order by creditos desc resultado: creditos 9 6 6 6 descripcion Fundamentos de la Programación Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente Puede aplicarse más de un criterio de ordenación: select creditos, descripcion from asignaturas order by creditos, descripcion resultado: creditos 4.5 6 6 6 9 descripcion Historia de la Informática Diseño y Gestión de Bases de Datos Fundamentos de las Bases de Datos Programación Concurrente Fundamentos de la Programación 11 Constantes Se pueden explicitar constantes en la orden select de forma que dicho valor aparezca en todas las filas: select 'La asignatura ', descripcion, ' tiene ', creditos, ' creditos' from asignaturas order by creditos resultado: 'laasignatura' La asignatura La asignatura La asignatura La asignatura La asignatura 12 descripcion HISTORIA DE LA INFORMATICA FUNDAMENTOS DE LAS BASES DE DATOS DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 'tiene' creditos 'créditos’ tiene 4.5 créditos tiene 6 créditos tiene 6 créditos tiene 6 créditos tiene 9 créditos BD Proveedores LA BASE DE DATOS PROVEEDORES Objetivos: • Ser capaz de interpretar un esquema de base de datos relacional (concretamente, el propuesto para las prácticas de la asignatura: Proveedores) Se detalla el esquema lógico que describe la BD de PROVEEDORES, ya creada y a disposición del alumno, intentando que comprenda su significado, el sistema real que pretende representar. El esquema lógico es la referencia que permite construir las órdenes select con las que interrogar a la BD. Las extensiones de cada relación se incluyen como ayuda para comprobar la corrección de las órdenes select utilizadas. 13 LA BASE DE DATOS PROVEEDORES TABLA VENDEDOR COLUMNAS ( numvend NUMBER(4), nomvend VARCHAR2(30), nombrecomer VARCHAR2(30), telefono CHAR(11), calle VARCHAR2(30), ciudad VARCHAR2(20), provincia VARCHAR2(20) ) ( numpieza VARCHAR2(16), nompieza VARCHAR2(30), preciovent NUMBER(9,2)) RESTRICCIONES Clave Primaria: (numvend) PRECIOSUM ( numpieza VARCHAR2(16), numvend NUMBER(4), preciounit NUMBER(9,2), diassum NUMBER(3), descuento NUMBER(2)) Clave Primaria: (numpieza, numvend) Clave Ajena: (numpieza)→ PIEZA, Clave Ajena: (numvend)→ VENDEDOR PEDIDO ( numpedido NUMBER(5), numvend NUMBER(4), fecha DATE ) Clave Primaria: (numpedido) Clave Ajena: (numvend)→ VENDEDOR LINPED ( numpedido NUMBER(5), numlinea NUMBER(2), numpieza VARCHAR2(16), preciocompra NUMBER(9,2), cantpedida NUMBER(4), fecharecep DATE, cantrecibida NUMBER(4)) Clave Primaria: (numpedido, numlinea) Clave Ajena: (numpedido)→ PEDIDO Clave Ajena: (numpieza)→ PIEZA INVENTARIO ( numpieza VARCHAR2(16), numbin NUMBER(10), cantdisponible NUMBER(5), fecharecuento DATE, periodorecuen NUMBER(2), cantminima NUMBER(5) ) Clave Primaria: (numbin) Clave Alternativa: (numpieza) Clave Ajena: (numpieza)→ PIEZA PIEZA Clave Primaria: (numpieza) La base de datos pretende reflejar la política de compras de una empresa de distribución. Se compran (tablas PEDIDO y LINPED) ciertas mercancías a los distintos proveedores (tabla VENDEDOR) y son vendidas posteriormente al público o a otros distribuidores (que no hemos considerado en la BD) Básicamente, las tareas que se pretenden mecanizar son las siguientes (entre paréntesis aparecen las tablas directamente relacionadas con cada una): • Lista de suministradores (vendedor). Los datos de los proveedores que nos suministran la mercadería que, posteriormente, es vendida al público en general. • Catálogo de venta (pieza) Las piezas que distribuye nuestra empresa y el precio de venta al público de las mismas. 14 • Lista de precios de suministro (preciosum, vendedor, pieza). Conocer los precios a los que los proveedores nos podrían suministrar las piezas. Es información histórica cuyo origen no nos preocupa. No se debe confundir esta información con la de los pedidos: los artículos almacenado en preciosum puede que no se hayan pedido nunca y, si se ha hecho, que hayan sido comprados a un precio distinto porque se negociara en ese instante con cualquiera de los suministradores. • Control de pedidos (pedido, linped, vendedor, pieza). De aquellas mercancías que se solicitan a los proveedores, controlar si se han servido en el tiempo estimado y en la cantidad pedida. Cada pedido consta de: • Cabecera de pedido (tabla pedido), donde se especifica qué vendedor nos ha suministrado el pedido completo, y la fecha en que se realizó el pedido. • Líneas de pedido (tabla linped), donde un conjunto de líneas pertenecientes a un mismo pedido se numeran desde la número 1 en adelante. Contiene el código de pieza que sirvió el proveedor, la cantidad que se le pidió y la cantidad que realmente ha servido a nuestra empresa y la fecha en la que se recibió, así como el precio al que se le compro (puede ser diferente al estipulado en preciosum). Sólo aquellas piezas que aparezcan en una línea de pedido han sido solicitadas al correspondiente vendedor y, si la cantidad recibida es mayor que cero, habrán sido recibidas por la empresa en esa cantidad. • Control de existencias (inventario, pieza). Mediante la confección de un inventario, donde cada entrada, que corresponde a un único artículo, es el recuento real de existencias. 15 tabla VENDEDOR numvend 1 2 3 4 5 6 7 8 9 10 11 12 13 8001 8002 8003 100 101 102 200 55 201 nomvend AGAPITO LAFUENTE DEL CORRAL LUCIANO BLAZQUEZ VAZQUEZ GODOFREDO MARTIN MARTINEZ JUANITO REINA PRINCESA JUANITO REINA PRINCESA MANOLO PIEDRA POMEZ MANUEL PEREZ RODRIGUEZ LUISA PINTO HEREDIA CHEMA PAMUNDI GUSTAVO DE BASICA MARIO DUQUE LIZONDO JOSE ANTONIO MARTINEZ JUAN MANUEL GOMEZ SANTISTEBAN JUAN RODRIGUEZ JUAN JUAN MARTINEZ GARCIA LUIS RODRIGUEZ SALA PEDRO GRACIA MORALES SALVADOR PLA GARCIA SOLEDAD MARTINEZ ORTEGA SEVERINO MARTIN MARTINEZ LUIS GARCIA SATORRE MANUEL ORTUÑO LAFUENTE nombrecomer telefono calle Ciudad provincia MECEMSA 96-5782401 Avda. Valencia 3205 ALICANTE ALICANTE HARW S.A. 96-3232321 GENERAL LACY, 15 2 B ALICANTE ALICANTE MECEMSA 96-4141722 AVDA. VALENCIA 3372 ALICANTE ALICANTE HARW S.A. 903-696969 LO ANGELE LOS EU'S LA DEAQUI 98-5363636 GIJON ASTURIAS HUMP S.A. 96-5660727 AVIACION 92, 3 I SAN VICENTE ALICANTE DONDEQUIERAS, 1000, 13F S. FRANCISCO DE ASIS, 10 1 SOFTHARD DISTRIBUIDORA S.A. LA MEJOR S.A. OLE ESPAÑA, S.A. OLE ESPAÑA, S.A. 98-5696969 ARZOBISPO LOACES 999-2014455 BANESTOESSOFT S.L. OXFORD BLUES QUINTANAR DE LA ORDE NEW ORLEANS RIVAS VACIAMADRID RIVAS VACIAMADRID LOUISSIANA MADRID MADRID 98-0101010 MOROS, 19 GIJON ASTURIAS OLE ESPAÑA, S.A. 3667788 COLON, 21 VALENCIA VALENCIA OLE ESPAÑA, S.A. 3667789 COLON, 21 VALENCIA VALENCIA ALMORADI ALICANTE HALA S.A. HARW S.A. 3334455 CISCAR, 5 VALENCIA VALENCIA HARW S.A. 3335588 SALAMANCA, 102 VALENCIA VALENCIA SALAMANCA, 100 VALENCIA VALENCIA SOFT S.A. TABAC & SOFT 5661100 MAYOR, 44 SAN VICENTE ALICANTE ASX. S.A. 87879998 PEREZ GALDOS, 54 ALICANTE ALICANTE SEVESOFT 5779988 GENERAL LACY, 17 ALICANTE ALICANTE HARW S.A. 5889944 POETA ALONSO, 12 ALICANTE ALICANTE HALA S.A. 5660788 MAYOR, 64 SAN VICENTE ALICANTE tabla PIEZA numpieza A-1001-L C-1002-H C-1002-J C-400-Z DD-0001-210 DD-0001-30 DK144-0001 DK144-0002-P FD-0001-144 FD-0002-720 M-0001-C M-0002-C M-0003-C O-0001-PP O-0002-PP P-0001-33 T-0001-IBM T-0002-AT T-0003-AT X-0001-PC 16 TOLEDO nompieza MOUSE ADL 3B FILTRO PANTALLA X200 DISCO DURO WESTERN DIG 210M 28 DISCO DURO 30M SEAGATE DISKETTE 1.44 PANASONIC PACK DISKETTE 144 PANASONIC FLOPPY 1.44 IBM FLOPPY 720K IBM MONITOR SYNCMASTER 3 COLOR MONITOR COLOR SONY BT MONITOR IBM 3570 COLOR PEGATINAS CONCIERTO JEVI PACK PEGATINAS CONCIERTO JEVI PLACA INTEL 33Mz TECLADO XT IBM TECLADO AT SUSUSU TECLADO AT HP TECLADO ESTANDAR PC preciovent 7,00 4,00 7,00 18,00 250,00 200,00 1,10 10,00 180,00 150,00 170,00 350,00 400,00 20,00 100,00 350,00 110,00 55,00 120,00 70,00 tabla PEDIDO numpedido 1 2 3 4 5 6 7 numvend 1 1 2 2 1 5 8002 fecha 05/05/1992 11/10/1992 15/10/1992 16/10/1992 22/10/1992 22/08/1995 02/10/1992 tabla LINPED numpedido 1 1 1 1 1 2 2 3 3 4 5 6 6 7 numlinea 1 2 3 4 5 1 2 1 2 1 1 1 2 1 numpieza M-0001-C P-0001-33 FD-0001-144 DD-0001-210 T-0002-AT DK144-0002-P T-0002-AT DD-0001-210 P-0001-33 O-0002-PP T-0002-AT O-0001-PP O-0002-PP C-400-Z preciocompra 300,00 210,00 135,00 150,00 31,00 5,45 30,00 146,00 210,00 99,00 15,00 15,00 99,00 7,00 cantpedida 10 20 20 20 22 100 1 15 3 10 15 1000 2000 45 fecharecep 10/05/1992 10/05/1992 10/05/1992 10/05/1992 17/10/1992 15/10/1992 15/10/1992 17/10/1992 17/10/1992 17/10/1992 11/06/1993 25/08/1995 25/08/1995 09/10/1992 cantrecibida 10 18 20 20 22 101 1 15 3 10 13 1000 1998 8 tabla INVENTARIO numpieza DD-0001-30 P-0001-33 O-0002-PP M-0001-C M-0003-C DD-0001-210 FD-0001-144 numbin 1 2 3 4 5 6 7 cantdisponible 120 10 110 15 2 10 10 fecharecuento 15/10/1990 15/10/1992 15/10/1992 15/10/1992 20/10/1992 12/11/1992 12/11/1992 periodorecuen 1 1 2 1 2 2 cantminima 15 5 3 2 0 1 0 17 tabla PRECIOSUM numpieza A-1001-L A-1001-L A-1001-L A-1001-L C-1002-H C-1002-J C-400-Z C-400-Z DD-0001-210 DD-0001-210 DD-0001-210 DD-0001-30 DK144-0001 DK144-0002-P DK144-0002-P FD-0001-144 FD-0001-144 FD-0001-144 FD-0002-720 M-0001-C M-0001-C M-0002-C M-0002-C M-0003-C M-0003-C M-0003-C O-0001-PP O-0001-PP O-0001-PP O-0002-PP O-0002-PP O-0002-PP O-0002-PP P-0001-33 P-0001-33 P-0001-33 P-0001-33 P-0001-33 T-0001-IBM T-0001-IBM T-0001-IBM T-0002-AT T-0002-AT T-0002-AT T-0002-AT T-0002-AT T-0002-AT T-0003-AT T-0003-AT 18 numvend 3 4 100 1 1 1 1 8002 1 2 101 1 1 1 2 1 102 55 1 1 3 9 1 3 4 1 5 55 1 2 5 101 1 2 1 4 3 5 2 100 1 1 2 4 5 100 201 1 3 preciounit 5,00 4,90 4,00 2,00 0,50 1,50 8,50 7,00 150,00 170,00 140,00 120,00 0,56 5,60 5,50 130,00 136,00 120,00 60,00 155,00 180,00 300,00 150,00 350,00 280,00 200,00 19,50 15,00 15,00 99,00 98,75 80,00 75,00 210,00 250,00 280,00 250,00 280,00 90,00 95,00 90,00 30,00 35,00 25,00 33,00 34,00 30,00 77,50 81,45 diassum 1 1 3 3 2 2 4 3 3 5 15 4 3 3 5 3 3 10 3 3 7 1 10 2 7 7 1 7 1 1 1 10 1 5 3 7 2 3 5 5 15 3 5 7 3 2 1 3 descuento 5 15 12 14 7 13 10 15 5 15 15 12 10 10 7 5 5 CONSULTAS SELECT1 1. Obtener todos los números de piezas de las piezas de la base de datos. 2. Nombre de todas las piezas con un precio de venta menor que 1000. 3. Número, nombre y precio de venta de las piezas de precio de venta mayor que 10 o menor que 1 euros, ordenadas de menor a mayor precio. 4. Para cada pieza de la que se conozca algún suministrador, obtener el número de pieza y el descuento, en orden descendente del valor de descuento. 5. Nombre de los vendedores con número de vendedor menor que 6. 6. Modificar el requerimiento anterior para eliminar duplicados. 7. Número y nombre de los vendedores con número de vendedor menor que 6. 8. Obtener todos los números de los vendedores de los que se sepa que pueden suministrar alguna pieza. 9. Vendedores de la provincia de Alicante. 10. Nombre y empresa de los vendedores de la Comunidad Valenciana. 11. Números de vendedores y días que tardarían en suministrar la pieza 'P-0001-33' 12. Códigos de pieza solicitados en el pedido 1, ordenados de mayor a menor precio de compra. 13. Números de pedido y números de vendedor, para los pedidos solicitados el 15 de octubre de 1992. 14. Códigos de pieza de los que se sabe que algún vendedor nos podría hacer descuento. 15. Códigos de pieza, de posible suministrador y precio de suministro, ordenados por código de vendedor y código de pieza. 19 20 select 2 CONSULTAS SOBRE VARIAS TABLAS Objetivos: • Poder relacionar distintas tablas de la BD para obtener información más compleja. Contenidos • Utilización de más de una tabla. • Nombres cualificados de atributo. • Sinónimos temporales de tabla. • Tipos de datos: dominios. • Resolución de requerimientos UTILIZACIÓN DE MÁS DE UNA TABLA Para la resolución de la mayoría de requerimientos es necesario trabajar con información que se obtiene de relacionar varias tablas. La forma de especificar qué tablas vamos a consultar es construir una lista de nombres de tablas en la cláusula FROM. Si seleccionamos la BD Ejemplo, podemos preguntar por el nombre de los profesores y la descripción de las asignaturas que imparten; esta información se encuentra almacenada en la tabla imparte, que relaciona las claves primarias de cada una de las tablas asociadas por tal relación. select nombre, descripcion from asignaturas, imparte, profesores where profesores.dni = imparte.dni and asignatura = codigo resultado: nombre EVA GOMEZ EVA GOMEZ RAFAEL ROMERO descripcion Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente En primer lugar, solicitamos nombre (del profesor) y descripcion (de la asignatura). El primer atributo se encuentra en la tabla profesores, y el segundo en la de asignaturas. La relación entre ambas tablas se encuentra en la tabla imparte, que asocia dni de profesor con codigo de asignatura que imparte. Así, para obtener la información que precisamos, necesitamos involucrar a las tres tablas al mismo tiempo. Podemos pensar, por clarificar el mecanismo por el que se obtiene este resultado, que el SGBD recorre la tabla de profesores, tupla por tupla, y busca el valor de dni de cada una en la tabla imparte. Si encuentra tal valor, en esa tupla de imparte en que lo ha encontrado, aparecerá el código de asignatura, en la columna nominada como asignatura; buscando en la tercera tabla, asignaturas, obtendrá la descripcion y finalmente mostrará en pantalla el nombre y la descripción que le corresponde. 21 Nótese que no aparece MANUEL PALOMAR, o la asignatura HISTORIA DE LA INFORMÁTICA, puesto que ni el primero (en nuestra BD) imparte asignatura alguna, ni la segunda es impartida por ningún profesor (de los conocidos por nuestro sistema). ¿Qué pasaría si no utilizáramos la cláusula where para enlazar las tablas? Supongamos el siguiente requerimiento: select asignatura, nombre from profesores, imparte resultado: asignatura FBD FBD FBD DGBD DGBD DGBD PC PC PC nombre EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO Si no indicamos nada en la cláusula where la información que obtenemos es simplemente la combinación de cada tupla con todas las demás: si hay 3 tuplas en imparte y otras 3 en profesores, la cardinalidad de la relación resultante es 3 x 3 = 9 tuplas. Si en la cláusula from pusiéramos, además, la tabla asignaturas, el resultado final tendría 3 x 3 x 5 = 45 tuplas. Veamos en detalle como funciona la orden select-from-where para el caso de la siguiente consulta (códigos de asignaturas y nombre de los profesores que las imparten)1: select asignatura, nombre from profesores, imparte where profesores.dni = imparte.dni resultado: asignatura FBD DGBD PC nombre EVA GOMEZ EVA GOMEZ RAFAEL ROMERO El SGBD primero combinaría todas las tuplas con todas de las tablas especificadas en el from: dni 21111222 21222333 21333444 21111222 21222333 21333444 21111222 21222333 21333444 1 nombre EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO categoria TEU TEU ASO6 TEU TEU ASO6 TEU TEU ASO6 ingreso 01/10/1993 16/06/1989 16/06/1992 01/10/1993 16/06/1989 16/06/1992 01/10/1993 16/06/1989 16/06/1992 dni 21111222 21111222 21111222 21111222 21111222 21111222 21333444 21333444 21333444 asignatura FBD FBD FBD DGBD DGBD DGBD PC PC PC Esto no es necesariamente real, una de las ventajas de utilizar un SGBD es que las consultas se procesan de manera eficiente y de forma totalmente transparente para el usuario. 22 Por lo especificado por la where eliminaría aquellas tuplas que no cumplieran la condición, y nos quedaría: dni 21111222 21111222 21333444 nombre EVA GOMEZ EVA GOMEZ RAFAEL ROMERO categoria TEU TEU ASO6 ingreso 01/10/1993 01/10/1993 16/06/1992 dni 21111222 21111222 21333444 asignatura FBD DGBD PC Y por último, las columnas especificadas en la select determinarían el resultado final: asignatura nombre FBD DGBD PC EVA GOMEZ EVA GOMEZ RAFAEL ROMERO NOMBRES CUALIFICADOS DE ATRIBUTO Si observamos la sentencia select anterior, al comparar los dni que aparecen en profesores y en imparte hemos utilizado el nombre de la tabla a la que pertenecen cada uno, profesores.dni e imparte.dni. Si en el conjunto de columnas de todas las tablas que se especifican en la cláusula from existen varias con nombres iguales, deberemos especificar en todo momento la tabla de la que queremos extraer la información. Caso de no existir ambigüedad, no es necesario utilizar el nombre de la tabla; ni asignatura ni codigo se utilizan en otras tablas. Si deseamos conocer el dni y el nombre de los profesores que imparten alguna asignatura, buscaremos en imparte los dni de los profesores (son los que tienen al menos una asignatura asignada), y con este valor obtendremos el nombre en profesores. select dni, nombre from profesores, imparte where profesores.dni = imparte.dni resultado: ERROR Al especificar que nos muestre en pantalla el dni del profesor, el SGBD entra en conflicto puesto que no sabe si nos referimos al de la tabla profesores o al de la tabla imparte. Utilizaremos el nombre completo de la columna (es indiferente, en este caso, de qué tabla): select profesores.dni, nombre from profesores, imparte where profesores.dni = imparte.dni resultado: dni 21111222 21111222 21333444 nombre EVA GOMEZ EVA GOMEZ RAFAEL ROMERO Se recuerda que la ocurrencia EVA GOMEZ está relacionada con dos asignaturas, y es por eso que aparece duplicada en este resultado. La forma de evitar tuplas idénticas ya se mostró en la sesión anterior. 23 SINÓNIMOS TEMPORALES DE TABLA Para facilitar la escritura de las sentencias select (entre otros posibles motivos) se pueden utilizar alias temporales, nombres alternativos de las tablas. Se especifican en la lista de tablas del from, antes de la “,” que separa el nombre de la tabla en cuestión de la siguiente. select distinct p.dni, nombre from profesores p, imparte i where p.dni = i.dni resultado: dni 21111222 21333444 nombre EVA GOMEZ RAFAEL ROMERO CONSULTAS SELECT2 1. Obtener el número de pieza junto con el nombre de todas las provincias desde las que puede sernos suministrada, en orden descendente del número de pieza. 2. Modificar el requerimiento anterior para eliminar duplicados. 3. Lista el nombre y número de las piezas. 4. Obtener el nombre y número de proveedores de la provincia de Valencia. 5. Obtener el nombre y número de proveedores de la provincia de Valencia a los que se les ha solicitado un pedido. 6. Obtener los números de línea y su precio de compra del pedido número 1. 7. Obtener todas las piezas que se recuenten el 15 /10/1992. 8. Obtener número y nombre de todas las piezas recibidas el 1 de Mayo de 1992. 9. Precio unitario de suministro del número de pieza A-1001-L y el vendedor 100. 10. Nombres de proveedores que puedan suministrarnos la pieza numero A-1001-L 11. Obtener nombre, teléfono, y ciudad del vendedor que puede suministrarnos piezas con valor mayor de 100. 12. Obtener los vendedores que pueden suministrarnos piezas con un descuento de más de 10%. 13. Obtener los números de pedido del vendedor número 1. 14. Obtener los vendedores ordenados alfabéticamente en orden descendente. 15. Ídem en orden ascendente. 16. Obtener los números de pieza de las que conozcamos algún vendedor que nos la pueda suministrar. 17. Número y nombre de las piezas que puedan suministrarnos el vendedor número 2 y el 4 (no necesariamente que las puedan suministrar los dos). 18. Piezas que nos puedan suministar los vendedores de la empresa Harw S.A. 24 19. Número, nombre y precio de venta de las piezas que han sido compradas en un pedido servido por el vendedor 1. 20. Número y nombre de vendedor, y pieza que ha sido comprada a un precio mayor que el estipulado en la lista de precios de suministro. 21. Número de pieza y número y nombre de vendedor de aquellas piezas cuyo precio de venta es mayor que 50 o su descuento de suministro es mayor que 10. 22. Pedidos y datos del vendedor cuya fecha de pedido no sea el 22 de octubre de 1992. 23. Precios a los que nos pueden ser suministradas las piezas DD-0001-210 y FD-0001-144, y número y nombre de los vendedores que las podrían suministrar a esos precios. 25 26 select 3 EXPRESIONES DE SELECCIÓN DE FILAS Objetivos: • Comparaciones de cadenas de caracteres. Contenidos • BETWEEN, IN • LIKE, subcadenas. Construcción de expresiones de selección de filas utilizando rangos, listas, y funciones de comparación de cadenas de caracteres. RANGOS Expresiones del tipo 10 <= x <= 100 se pueden construir utilizando el operador de construcción de rangos BETWEEN. La sintaxis de tal subexpresión de la cláusula where es la siguiente: expresión [NOT] BETWEEN expresión AND expresión Por ejemplo, deseamos conocer los créditos y descripción de las asignaturas cuyo número de créditos está entre 5 y 8. select creditos, descripcion from asignaturas where creditos between 5 and 8 resultado: creditos 6 6 6 descripcion Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente LISTAS Mediante el operador IN se puede buscar un determinado valor en una lista construida usando constantes. expresión [NOT] IN (listaValores) 27 Descripción de las asignaturas FBD y DGBD: select descripcion from asignaturas where codigo in ('FBD', 'DGBD') resultado: descripcion Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Nombre de los profesores que no imparten HI, FBD o DGBD: select nombre from profesores p, imparte i where p.dni = i.dni and asignatura not in ('HI', 'FBD', 'DGBD') resultado: nombre RAFAEL ROMERO Fijémonos en que MANUEL PALOMAR, que no imparte ninguna de las asignaturas objeto de la búsqueda, tampoco aparece en la tabla resultado puesto que su dni no aparece en la tabla IMPARTE. SUBCADENAS DE CARACTERES Podemos preguntar por subcadenas dentro de columnas de tipo carácter. Para ello utilizaremos los operadores LIKE o MATCHES, que soportan la siguiente sintaxis: columna [NOT] LIKE 'cadena' La cadena de caracteres cadena admite los comodines % y _ , equivalentes en uso a los comodines de MS-DOS * y ?, es decir, el primero indica una cadena de caracteres de cualquier longitud, y el segundo un carácter cualquiera. Profesores que atiendan al nombre de 'RAFA': select * from profesores where nombre like 'RAFA%' resultado: dni 21333444 nombre RAFAEL ROMERO Código de las asignaturas de 'Bases de Datos' select codigo from asignaturas where descripcion like '%BASES DE DATOS%' resultado: 28 codigo FBD DGBD categoria ASO6 Código de las asignaturas, siendo tal código de 2 caracteres: select codigo from asignaturas where codigo like '__ ' (2 subrayados seguidos de 3 espacios en blanco: codigo es un CHAR(5) resultado: codigo HI PC FP VALORES NULOS Podemos interrogar a la BD de datos en busca de valores desconocidos (información faltante) mediante el operador IS NULL, cuya sintaxis es: columna IS [NOT] NULL Código y créditos de las asignaturas de las que conocemos su número de créditos: select codigo, creditos from asignaturas where creditos is not null resultado: codigo creditos HI FBD DGBD PC FP 4.5 6 6 6 9 RESUMEN DE OPERADORES Recopilamos todos los operadores y conectivas lógicas vistos hasta ahora para la construcción de expresiones condicionales: = > < >= <= <> IS NULL AND OR NOT BETWEEN IN LIKE {%,_} 29 CONSULTAS SELECT3 1. Obtener el nombre de las piezas que puedan ser suministradas por aquellos proveedores cuyo nombre empiece por S. 2. Obtener el nombre de las piezas que puedan ser suministradas por proveedores cuyo nombre empiece por S, y se llamen de apellido2 Martínez o Martín. 3. Obtener los nombres de los vendedores de las provincias de Valencia, Castellón o Alicante. 4. Nombres de vendedores que empieza su nombre por J. 5. Nombres de vendedores que termina su nombre por Z. 6. Nombres de vendedores que se apellidan López. 7. Nombre de vendedores que el nombre empieza por M seguido de cualquier carácter simple, una R y cualquier cadena de n caracteres. 8. Obtener los vendedores de la provincia de Valencia o Alicante que su nombre empieza por J o por M y tienen un número de vendedor entre 1 y 100. 9. Listar los nombres y números de vendedores así como el número y nombre de las piezas que pueden suministrar, para los vendedores de la provincia de Valencia o Alicante. 10. Obtener los nombres de pieza que pueden suministrar los vendedores de apellido 'García'. 11. Piezas3 que sabemos que nos puede suministrar algún vendedor. 12. Obtener todos los vendedores que tengan teléfono. 13. Listar las piezas con un descuento entre 1 y 10 cuyo nombre contenga una O y que se las hayamos solicitado a proveedores cuyo número oscile entre el 1 y el 1000. 14. Obtener los nombres de vendedores en orden alfabético. 15. Obtener nombre de vendedores y nombre de piezas que pueden suministrar ordenado en orden alfabético. 16. Obtener todos los nombres de piezas que pueda suministrar el vendedor 100, el 300 y/o el 400 con un precio de venta entre 10 y 1000, y un precio unitario entre 1 y 500. 17. Obtener el número de pieza y el precio de los monitores. 18. Nombre de las piezas que pueden sernos suministradas desde la Comunidad Valenciana. 19. Obtener los vendedores que viven en la calle Ciscar o Salamanca y de la Empresa Harw S.A. 20. Obtener nombres de vendedores y números de pieza que nos pueden suministrar, de aquellos vendedores cuyo apellido comienza por Martín, y ordenados alfabéticamente. 2 Evidentemente, la BD no diferencia entre nombre y apellido primero y segundo, por lo que se ha de tratar como subcadenas dentro del valor del atributo. 3 Cuando no se especifica un atributo concreto, se entiende que se pide toda la información disponible en la BD de los objetos solicitados. 30 select fecha FUNCIONES DE FECHA4 Objetivos: • Construir condiciones de selección de filas utilizando atributos de tipo fecha. Contenidos • TO_CHAR() • TO_DATE() • SYSDATE • ADD_MONTHS() • MONTHS_BETWEEN() FUNCIONES DE FECHA Se presentan a continuación distintas funciones de manejo de fechas y hora, que se pueden utilizar tanto en la lista de columnas que aparecerán en la tabla resultado de la select como en la construcción de expresiones de la where. En general, la comparación entre fechas se hace directamente. Por ejemplo: select nombre from profesores where ingreso < '23/12/1989'; select nombre from profesores where ingreso < '23/12/1989'’ resultado: nombre MANUEL PALOMAR Pero si necesitamos hacer transformaciones sobre un determinado dato (extraer parte de una fecha, cambiar el formato de visualización, calcular días, etc.) entonces debemos ayudarnos de estas funciones. TO_CHAR(fecha [, formato]) Convierte la fecha de tipo DATE a un valor VARCHAR2 en el formato especificado en "formato" Convierte la cadena de caracteres "cadena" de tipo TO_DATE(cadena [, formato]) CHAR a un valor de tipo DATE con el formato especificado en "formato" SYSDATE Devuelve la fecha actual del sistema ADD_MONTHS(fecha,n) Devuelve la fecha especificada con n meses más MONTHS_BETWEEN(fecha1,fecha2) Devuelve los meses transcurridos entre fecha1 y fecha2 4 Aunque todas las demás sesiones de prácticas cumplen con el estándar SQL, los tipos de datos de fecha y hora y las funciones que los manejan no suelen estar igualmente implementadas en todos los SGBD, por lo que esta sesión es únicamente aplicable a Oracle. 31 FORMATOS DE FECHA Las funciones TO_CHAR() y TO_DATE() admiten distintos formatos de fecha que se pueden construir según una máscara especificada por el usuario. Dicha máscara es una cadena de caracteres entre comillas simples en la que se pueden utilizar los siguientes: ELEMENTO - / ' . ; : 'texto' D DAY DD DY MM MON MONTH Q YYYY Y,YYY YY SIGNIFICADO Marcas de puntuación y texto fijo que se reproduce en el resultado Día de la semana (1-7) Nombre del día de la semana Día del mes (1-31) Día del año (1-366) Mes (1-12) Nombre abreviado del mes Nombre completo del mes Cuatrimestre del año (1-4) Año con 4 dígitos Año con punto de millar Año con 2 dígitos Por ejemplo: select nombre, to_char (ingreso,'DD') from profesores where to_char(ingreso,'DD') < 15 select * from profesores where to_char(ingreso,'MM') < 6 select * from profesores where ingreso = sysdate Para obtener el número de días entre dos fechas basta con utilizar la operación resta select nombre, sysdate-ingreso from profesores CONSULTAS SELECT FECHA 1. Obtener el número de pieza de las piezas que se recuenten el 15/10/92. 2. Números de pieza de las piezas que se recuentan entre el 1 de Octubre de 1992 y el 31 de Octubre de 1992. 3. Número y fecha de los pedidos solicitados en el segundo semestre del 92. 4. Nombre de los vendedores que sirvieron piezas en la primera quincena de mayo del 92, ordenado alfabéticamente. 5. Número, nombre de vendedor y mes en que se les solicitó un pedido de discos duros. 6. Años en que se ha efectuado algún recuento. 7. Número y descripción de las piezas que sirvieron los proveedores los días 10 de cada mes. 8. Número y descripción de las piezas que sirvieron los proveedores en el 95 y cuyo precio de compra es superior al precio de suministro que ellos ofertaban. 9. Número de pieza, descripción, fecha de recepción, cantidad recibida, de las piezas recibidas en el 95 y de precio de venta entre 50 y 100 euros. 32 create DEFINICIÓN DE DATOS Objetivos: • Introducir al alumno a la definición de datos. Contenidos • Las órdenes CREATE TABLE y DROP TABLE • Restricciones • La orden INSERT (1) • Información sobre las restricciones de una tabla IMPORTANTE Para ésta y las sesiones que traten de crear y borrar tablas, e insertar, modificar o eliminar datos, es necesario entrar al sistema con un usuario con permisos suficientes y diferente para cada puesto (si dos alumnos entraran con el mismo usuario estarían trabajando en el mismo espacio de trabajo y colisionarían al crear y mantener sus tablas). Por ello, se debe iniciar la sesión como: usuario: bdixx contraseña: bdixx servicio: oracle donde xx es el número del ordenador en el aula (01, 02, ..., 10, 11, ... 25 ...) Dado que el número de usuarios es limitado, al terminar cada grupo de prácticas, los usuarios serán “limpiados” por lo que los datos manejados durante la sesión serán borrados y no estarán disponibles para las semanas siguientes. LA ORDEN CREATE TABLE La definición de tablas es el primer paso en la creación de una base de datos. El conjunto de descripciones de tablas conforma el esquema de base de datos y representa a un sistema de información concreto. Supongamos que vamos a implementar un esquema de base de datos relacional de profesores, asignaturas (sólo es un listado de profesores y asignaturas, sin relaciones entre ellos). En primer lugar debemos decidir cuáles son los atributos de cada uno de ellos y sus tipos de datos: PROFESORES (DNI: varchar2(10), nombre: varchar2(40), categoria: char(4), ingreso: datetime) ASIGNATURAS (codigo: char(5), descripcion: varchar2(35), creditos: number(3,1) creditosp: number(3,1)) Para cumplir con las restricciones del modelo relacional, además, debemos elegir las claves primarias adecuadas5: DNI para profesores y codigo para asignaturas. Obviamente, la forma que tienen estas tablas ha sido una decisión nuestra como diseñadores de esta base de datos concreta, en otra situación hubiéramos, probablemente, decidido definir otros atributos y otras tablas. La orden CREATE TABLE nos permite crear cada una de las tablas necesarias para nuestra base de datos: CREATE TABLE nombreTabla ( {listaColumnas} [,{restricciones}] ) La lista de columnas, en su forma más sencilla, es un conjunto de expresiones (tantas como columnas deseemos, y separadas por comas) del tipo: columna tipoDatos[,columna tipoDatos[, ...]] RESTRICCIONES Las restricciones son reglas, que normalmente se establecen en el momento de crear una tabla, para garantizar la integridad de los datos. Básicamente, las restricciones obligan a cumplirse ciertas reglas cuando una fila es insertada, borrada o modificada, de forma que la operación se llevará a efecto sólo si se cumplen las restricciones definidas en la tabla. Podemos contemplar los siguientes tipos de restricciones de integridad de datos: • NOT NULL: especifica que la columna no puede contener un valor nulo. • PRIMARY KEY: identifica de manera única a cada fila de la tabla mediante una o varias columas, estas columnas que forman la clave primaria no pueden tener valores nulos. • FOREIGN KEY: establece una relación entre una(s) columna(s) de la tabla y otra(s) columna(s) de la tabla referenciada, siendo esta última(s) columna(s) la PRIMARY KEY. • CHECK: especifica una condición que se debe evaluar a “cierto”. De las restricciones, sólo vamos a utilizar, de momento, la clave primaria, que puede contener tantas columnas como se necesiten: PRIMARY KEY (columna[,columna[, ...]]) 5 Todos los SGBDR permiten crear tablas sin restricciones de clave primaria, pero un correcto diseño de bases de datos incluirá claves ajenas que no se pueden definir si no existen sus correspondientes claves primarias. Las claves ajenas se introducen en la siguiente sesión. 35 Por ejemplo: create table profesores (DNI varchar2(10), nombre varchar2(40), categoria char(4), ingreso date, primary key (DNI));6 create table asignaturas (codigo char(5), descripcion varchar2(35), creditos number(3,1) creditosp number(3,1), primary key (codigo))7 resultado: 1 tabla creada 1 tabla creada Ahora ya podemos ejecutar una consulta sobre cualquiera de estas dos tablas: select * from profesores resultado: ninguna fila seleccionada El resultado de la creación es una tabla vacía, sin filas, lista para insertar datos en ellas (orden insert, a continuación). Al crear una tabla, el resultado es persistente, la tabla no “desaparece” cuando nos desconectamos del servidor (tampoco los datos que almacenamos en ella). Si queremos borrar una tabla debemos ordenárselo al SGBD mediante la orden DROP TABLE: DROP TABLE nombreTabla Por ejemplo: drop table asignaturas resultado: 1 tabla borrada Al utilizar esta orden nótese que también se eliminan los datos (las filas) que pudiera contener. Ahora podríamos volver a crear la tabla (sin filas), con los mismos o diferentes atributos, y volver a borrarla, y... LA ORDEN INSERT Para introducir datos nuevos en una base de datos vamos a utilizar la orden INSERT de SQL. Con la sintaxis que se muestra a continuación seremos capaces de introducir datos nuevos en cualquiera de las tablas que componen una determinada BD. En principio, veremos la expresión mínima de la orden, formada por dos cláusulas, into y values. INSERT INTO nombreTabla VALUES ( listaExpresiones ) Supongamos que en la base de datos anterior queremos dar de alta un nuevo profesor. Si dicho profesor tiene como dni el “55555555”, nombre “PATRICIO MARTÍNEZ”, categoría “TU” y fecha de incorporación “01/01/2000”, deberíamos ejecutar la siguiente orden. 6 Para facilitar su uso, los nombres de tabla y las columnas no deben incluir acentos o caracteres no habituales 7 El “punto y coma” es necesario para informar a Oracle de que una orden ha de ejecutarse y que, a continuación, se va a ejecutar otra orden distinta. Si sólo se escribe una orden no hace falta este caracter. No obstante, por la implementación del cliente Worksheet, se aconseja terminar todas las órdenes con punto y coma, incluso si sólo es una. 36 Insert into profesores values (‘55555555’,’PATRICIO MARTINEZ’,’TU’,’01/01/2000’); resultado: 1 fila creada Sólo se puede indicar una tabla en la que introducir datos, no se permite una lista de nombres de tabla para introducir datos en varias tablas a la vez. Para introducir datos en n tablas, habrá que ejecutar n sentencias INSERT. insert into profesores, asignaturas values (‘55555555’,’PATRICIO MARTINEZ’,’TU’, ’01/01/2000’, ‘BdI’,’BASES DE DATOS I’,6,0); resultado: ERROR falta la palabra clave values Lo mismo ocurre con las filas, sólo se puede indicar una lista de valores. Esto quiere decir que hay que ejecutar una orden insert por cada una de las filas que queramos almacenar en una tabla insert into profesores values (‘66’,’ERNESTO PEREZ’,’ASO6’, ’10/10/2001’); resultado: 1 fila creada Resultado El resultado que devuelve una orden INSERT, será siempre el número de filas insertadas, en el caso de que la ejecución haya sido correcta. Para los casos en que la ejecución de la sentencia viole alguna restricción de la BD y por tanto, su ejecución no sea correcta, el resultado indicará cuál es la restricción violada. El SGBD, cada vez que insertamos un nuevo dato en una tabla, se encarga de verificar las restricciones activas, en nuestro caso las claves primarias, que como sabemos, no admiten valores duplicados, ni valores nulos. insert into profesores values (‘66’,’PEPITO’,’XXX’, ’11/11/2006’); resultado: ERROR restricción única (BDI.SYS_C0033923) 8 violada VALUES Si no se va a dar valor a todas las columnas de la tabla se deberá indicar las columnas a las que se les dará valor. Así, si por ejemplo, sólo supiéramos el dni y el nombre del profesor que queremos dar de alta, ejecutaríamos la sentencia siguiente Insert into profesores (dni, nombre) values (‘88888888’, ‘ARMANDO SUAREZ’); resultado: 1 fila creada Es recomendable acostumbrarse a poner siempre las columnas a las que se va a dar valor, sean o no todas las de la tabla. Las razones que lo aconsejan son: 8 Nombre de la restricción. 37 • No habrá que fijarse en si se va a dar valor a todas o sólo a alguna de las columnas para acomodar la sintaxis de la sentencia INSERT. • Si por alguna razón se modifica la estructura de una tabla, es decir, se añaden columnas nuevas, y tenemos costumbre de no indicar las columnas cuando se inserta valor a todas, con la modificación dejarán de funcionar las sentencias que tuviéramos escritas. Existe la posibilidad de hacer uso del valor NULL. Puesto que NULL es la ausencia de valor, si lo asignamos como valor a una columna de una tabla, lo que estaremos haciendo es indicar que esa columna no tiene valor. La siguiente sentencia realiza la misma operación que la anterior. Insert into profesores (dni,nombre,categoria,ingreso) values (‘88888888’,’ARMANDO SUAREZ’, NULL, NULL); resultado: 1 fila creada La lista de valores se asigna a la lista de columnas, de forma que la primera columna toma el primer valor, la segunda el segundo y así sucesivamente. Es decir, las dos sentencias siguientes realizan exactamente la misma operación, aunque el orden de asignación es diferente. Insert into profesores (dni,nombre,categoria) values (‘88888888’,’ARMANDO SUAREZ’, NULL); resultado: 1 fila creada Insert into profesores (categoria,dni,nombre) values (NULL, ‘88888888’,’ARMANDO SUAREZ’); resultado: 1 fila creada Ésto apoya aún más el hecho de que sea aconsejable poner siempre la lista de columnas, ya que aún dando valor a todas las columnas de la tabla, si no las indicamos, la lista de valores deberá seguir el orden que esas columnas tienen internamente en la tabla. Es decir, estaremos obligados a mirar las columnas y su orden, para poder establecer el orden adecuado en la lista de valores. INFORMACIÓN SOBRE UNA TABLA Recordemos que ejecutar DESC nombreTabla o DESCRIBE nombreTabla, muestra información sobre las columnas que componen la tabla, el orden interno de las mismas en la tabla, y sus tipos de datos. INFORMACIÓN SOBRE LAS RESTRICCIONES DE UNA TABLA En el momento de crear una restricción, además de especificar las reglas que se deben cumplir, podemos dar un nombre a la misma. Para establecer los nombres de las restricciones, se suele seguir el siguiente convenio: ser nombres descriptivos y empezar, por ejemplo, por PK_ si se trata de una Primary Key o por FK_ si se trata de una Foreign Key o por C_ si se trata de una CHECK. No vamos a profundizar más en los nombres de las restricciones ni en la sintaxis para crearlos, pero sí que debemos saber que si no especificamos ningún nombre, Oracle asigna un nombre único a cada restricción con el formato SYS_Cn, siendo n un valor entero. 38 La sentecia DESC sólo muestra, a nivel de restricción, si una columna determinada admite o no nulos, pero no facilita ninguna información sobre otro tipo de restricciones. Para obtener la información relativa a otras restricciones definidas sobre una tabla se deberá ejecutar una consulta, sobre la tabla USER_CONSTRAINTS, del tipo siguiente: select constraint_name, constraint_type, search_condition from user_constraints where table_name =’nombreTabla’ 9 ; Donde • Constraint_name es el nombre de la restricción. • Constraint_type puede tomar distintos valores, P indica que la restricción es de clave primaria, R que es ajena y C una check. • Search_condition es la condición impuesta en caso de que la restricción sea de tipo check. Si, por ejemplo, quisiéramos saber las restricciones definidas sobre la tabla IMPARTE, ejecutaríamos la siguiente consulta select constraint_name, constraint_type, search_condition from user_constraints where table_name =’IMPARTE’; resultado: 9 (1) CONSTRAINT_NAME -----------------------------SYS_C0058701 SYS_C0058702 SYS_C0058703 C SEARCH_CONDITION - ----------------P R R nombreTabla debe indicarse en mayúsculas. 39 ÓRDENES CREATE 1. Crea una tabla de nombre XX con 2 columnas, col1 de tipo integer, y col2 de tipo char(3), con col1 como clave primaria. 2. consulta la tabla 3. inserta en la tabla la fila (1,’AA’) 4. ejecuta insert into XX values (‘BB’,2) 5. insert en la tabla la fila (2,’BB’) 6. consulta la tabla XX 7. cierra la sesión de Worksheet e identifícate de nuevo (“salte y vuelve a entrar”) 8. comprueba que, efectivamente, los datos siguen estando ahí 9. borra la tabla XX 10. consulta la tabla XX 11. crea una tabla YY con 3 columnas col1(integer), col2(char(2)) y col3(varchar2(10)), cuya clave primaria sea (col1, col2) 12. inserta los siguientes datos y consulta la tabla para ver los datos almacenados (1,’AA’,’primera’) (2,’AA’,’segunda’) (2,’BB’,’tercera’) (1,’AA’,’cuarta’) (NULL,NULL,’quinta’) (NULL,’CC’,’sexta’) (3,NULL,’séptima’) (0,’’,’octava’)10 (3,’AA’,NULL) 13. crea un listín de teléfonos con los siguientes datos: apodo, nombre, teléfono; rellénala con datos (4 filas será suficiente) 14. modifica la tabla anterior, añádele una columna más, grado de amistad, y vuelve a rellenarla de datos 15. crea una lista de la compra y rellénala de datos 10 40 “cero”, “dos comillas simples”,”octava” manipulación 1 MANIPULACIÓN DE DATOS (1) Objetivos: • Introducir al alumno en el concepto de clave ajena, influencia de las mismas en las sentencias Insert y Delete. Contenidos • La orden INSERT (2). Insertar las filas resultantes de una SELECT. • La orden DELETE. Borrar todas las filas de una tabla. Borrar determinadas filas. • Creación de tablas con claves ajenas. • Influencia de las claves ajenas en la sentencia INSERT y DELETE. Supongamos que en la BD Ejemplo existiera una tabla llamada OPTATIVAS que contuviera los códigos y los créditos de aquellas asignaturas de carácter optativo. Vamos a crear dicha tabla, eligiendo como clave primaria el código de la asignatura y poniendo además otra restricción, que todas las filas tengan un valor no nulo en la columna créditos create table optativas (asignatura char (5), creditos number(3,1) not null, primary key (asignaturas)) LA ORDEN INSERT Existe la posibilidad de insertar el resultado de una SELECT, en lugar de indicar la lista concreta de valores a insertar. Esto nos permite insertar varias filas en una tabla con una sola operación, en concreto, tantas filas como tuplas devuelva la SELECT. INSERT INTO nombreTabla [ ( listaColumnas ) ] consulta Supongamos que serán optativas todas las asignaturas que tengan menos de 9 créditos. Se trata de introducir los códigos de dichas asignaturas en la tabla OPTATIVAS. En este caso, como ya tenemos las asignaturas en la tabla ASIGNATURAS, tenemos dos opciones. Una opción es, hacer la SELECT e ir haciendo las INSERT una a una, copiando los datos de las filas obtenidas. Otra opción es insertar en una sola operación el resultado de la SELECT en la tabla OPTATIVAS. Insert into optativas (asignatura, creditos) select codigo, creditos from asignaturas where creditos < 9; 41 resultado: 4 filas creadas La SELECT deberá seleccionar tantas columnas como columnas pongamos en la lista de columnas de la parte insert y los tipos de datos de las columnas seleccionadas deberán coincidir con los tipos de datos de las columnas en las que se van a insertar esos valores. Insert into optativas (asignatura) select codigo, creditos from asignaturas where creditos < 9; resultado: ERROR demasiados valores Insert into optativas (asignatura,creditos) select codigo from asignaturas where creditos < 9; resultado: ERROR no hay suficientes valores Insert into optativas (asignatura,creditos) select dni,ingreso from profesores; resultado: ERROR tipos de dato inconsistentes Insert into optativas (asignatura) select codigo from asignaturas where creditos < 4; resultado:ERROR no se puede realizar una inserción NULL en (BDI.OPTATIVAS.CREDITOS) En esta última sentencia la restricción NOT NULL sobre la columna creditos impide que se realice la inserción de filas, para asegurar la integridad de los datos, evitando que se pongan valores nulos en esa columna. Por otra parte, es importante fijarse en que la sintaxis de la sentencia INSERT no permite utilizar a la vez una lista de valores y el resultado de una consulta. Insert into imparte (dni, asignatura) values (‘55555555’,select codigo from asignaturas); resultado: ERROR falta una expresión Pero sí dentro de la propia orden select: Insert into imparte (dni, asignatura) select ‘55555555’,codigo from asignaturas; resultado: 4 filas creadas LA ORDEN DELETE La sentencia DELETE nos permite borrar las filas contenidas en una tabla. DELETE [FROM] nombreTabla [WHERE condición] No se pueden borrar filas de varias tablas a la vez en una misma sentencia. Para borrar filas de varias tablas habrá que ejecutar tantas sentencias DELETE como de tablas queramos borrar. Delete from asignaturas a, imparte i where a.codigo = i.asignatura and i.dni=’21111222’; resultado: 42 ERROR comando SQL no terminado correctamente CLÁUSULA WHERE Si no se especifica ninguna condición, la sentencia causará el borrado de todas las filas de la tabla. Delete from asignaturas; resultado: 5 filas suprimidas En el caso de que se indique alguna condición, se borrarán sólo aquellas filas de la tabla que cumplan la condición o condiciones impuestas. Así, la siguiente sentencia, a diferencia de la anterior que borra todas las filas de la tabla asignaturas, hará que se borren sólo las asignaturas que tengan menos de 5 créditos. Delete from asignaturas where creditos < 5; resultado: 1 fila suprimida La condición indicada en la cláusula where puede ser tan complicada como se desee. Por ejemplo, la sentencia siguiente borra aquellas asignaturas que son impartidas por profesores con categoría de TEU. Delete from asignaturas where codigo in (select asignatura from imparte i, profesores p where i.dni = p.dni and p.categoria=’TEU’); Resultado: 1 fila suprimida CREACIÓN DE TABLAS CON CLAVES AJENAS Relacionemos ahora las tablas PROFESORES y ASIGNATURAS mediante la tabla IMPARTE, de forma que para cada profesor que tenga docencia, se indique en la tabla IMPARTE su dni junto con el código de la asignatura que imparta. Cada profesor tendrá tantas filas, en esta nueva tabla, como asignaturas imparta. IMPARTE ( dni : varchar2(10), asignatura : char(5) ) Clave primaria: (dni, asignatura) Clave ajena: dni → PROFESORES Clave ajena: asignatura → ASIGNATURAS Evidentemente, se deberá exigir que el valor que tenga la columna dni exista en la tabla PROFESORES, de la misma manera cada código de asignatura deberá existir en la tabla ASIGNATURAS, esto es lo que se conoce como integridad referencial y se consigue mediante las denominadas claves ajenas:. columna REFERENCES tabla La sentencia de creación de esta tabla, junto con sus restricciones de clave primaria y claves ajenas es create table imparte ( dni varchar2(10) references profesores, asignatura char(5) references asignaturas, primary key (dni,asignatura ) ); Con esta sintaxis a nivel de columna, cada clave ajena sólo puede estar formada por una sola columna. 43 Veamos otra sintaxis para definir claves ajenas, mediante las palabras reservadas FOREIGN KEY, que nos permite designar varias columnas como clave ajena. FOREIGN KEY (columna[,columna[, ...]]) REFERENCES tabla Con esta sintaxis, vamos a escribir una sentencia equivalente a la anterior create table imparte ( dni varchar2(10), asignatura char(5), primary key (dni,asignatura ), foreign key (dni) references profesores (dni), foreign key (asignatura) references asignaturas (codigo) ); Sea cual sea la sintaxis elegida para su definición, las columnas que conforman la clave ajena han de coincidir en número (y orden) y tipo de datos con la clave primaria de la tabla a la que se va a hacer referencia. Una restricción de integridad referencial designa una columna o combinación de columnas como clave ajena de una tabla (la tabla hija) y establece una relación entre ella y la clave primaria de otra tabla (la tabla padre11). Por ejemplo, en la última línea de la sentencia, la clave ajena asignatura hace referencia a la clave primaria codigo de la tabla padre asignaturas. Toda clave ajena, si no tiene un valor nulo, debe tener un valor que coincida con un valor existente en la tabla padre. CLAVES AJENAS: influencia en el INSERT En una tabla con claves ajenas, sólo se podrán insertar aquellas filas cuyas claves ajenas existan en la correspondiente tabla padre. En el siguiente ejemplo la inserción no es posible pues no existe la asignatura ‘AAA’. insert into imparte (dni, asignatura) values ('55555555','AAA'); resultado: ERROR restricción de integridad (BDI.SYS_C0058700) violada - clave principal no encontrada insert into imparte (dni, asignatura) values ('21333444','FP'); resultado: 1 fila creada CLAVES AJENAS: influencia en el DELETE Sólo se podrán borrar aquellas filas que no estén siendo referenciadas, a través de ninguna clave ajena, desde otra tabla. Si por ejemplo tenemos que la asignatura BDA es impartida por el profesor con dni 21111222, no se podrá borrar la asignatura si antes no se eliminan las líneas correspondientes a esa asignatura en la tabla imparte. Delete from asignaturas where codigo = ‘FBD’; resultado: ERROR:restricción de integridad (BDI.SYS_C0058700) violada - registro secundario encontrado 11 44 La tabla padre puede ser la misma tabla hija Para poder realizar esta operación, será necesario primero eliminar las filas de imparte que hagan referencia a esa asignatura. Una vez que la asignatura ya no está siendo referenciada desde ninguna otra tabla, puede ser eliminada. Delete from imparte where asignatura = ‘FBD’; resultado: 1 fila suprimida Delete from asignaturas where codigo = ‘FBD’; Resultado: 1 fila suprimida EJERCICIOS MANIPULACIÓN1 Si alguna de las sentencias no se puede realizar, explica el motivo del error 1. Partiendo del ejercicio 13 de la sesión anterior, deberemos tener la sentencia de creación de la tabla LISTIN, con las siguientes columnas: apodo, nombre, telefono, grado. Como clave primaria podemos elegir apodo. También tendremos las sentencias insert para incorporar algunas filas. Ejecutemos todo ello para tener la tabla LISTIN con algunas filas. 2. Crear la tabla AMISTAD con las columnas grado y descripcion , para reflejar los diferentes grados de amistad y su descripción: amigo, colega, etc. Por lo pronto vamos a crear sólo la tabla. Sin incorporar datos. 3. Borremos la tabla LISTIN. Y volvamos a crearla, pero añadiendo una restricción: que la columna grado sea clave ajena que referencie a AMISTAD. 4. Ejecutemos las sentencias del punto 1 para insertar algunas filas en LISTIN. 5. Mirando detenidamente las anteriores sentencias hagamos SÓLO los insert NECESARIOS en la tabla AMISTAD. 6. Volvamos a ejecutar las sentencias del punto 4. 7. Crear un nuevo grado de amistad en AMISTAD. 8. Borremos TODAS las filas de AMISTAD. Mira las filas de AMISTAD y explica que sucede. 9. Borremos ahora sólo una fila, la última que hemos añadido. 10. Borremos de AMISTAD la fila que más referencias tenga, hagamos una select de LISTIN y contemos visualmente. 11. Borremos las filas necesarias del LISTIN que nos permitan ejecutar el punto 10. 12. Volvamos a ejecutar el punto 10. 45 46 manipulación 2 MANIPULACIÓN DE DATOS (2) Objetivos: • Introducir al alumno en la orden UPDATE. • Practicar con la integridad referencial. Contenidos • Actualizar los valores existentes en tablas de la base de datos. • Actualizar los valores existentes en tablas de la base de datos a través de subconsultas. LA ORDEN UPDATE La sentencia UPDATE nos permite modificar la información contenida en una tabla. UPDATE nombreTabla [aliasTabla] SET columna=expresion [WHERE condición] No se pueden modificar varias tablas a la vez en una misma sentencia. Para modificar los valores de varias tablas varias habrá que ejecutar tantas sentencias UPDATE como de tablas queramos modificar. Update asignaturas a, imparte i set creditos= 2 where a.codigo = i.asignatura and i.dni=’21111222’; resultado: ERROR falta la palabra clave SET CLÁUSULA SET En la cláusula SET se especifican las columnas de la tabla cuyos valores se desean modificar y los nuevos valores que se van a asignar a dichas columnas. Por ejemplo, la siguiente sentencia hace que la columna créditos de la tabla asignaturas pase a tener valor 0. Update asignaturas set creditos = 0; resultado: 4 filas actualizadas Cuando se desea modificar más de una columna se indicará la lista de columnas y valores separadas por comas. En el ejemplo que se muestra a continuación, a la columna créditos se le asigna el valor 4 y a la columna créditosp el valor 2. Update asignaturas set creditos=4, creditosp=2; Resultado: 4 filas modificadas Debe existir concordancia entre los tipos de datos de las columnas y el de los valores asignados a las mismas. 47 Update asignaturas set creditos=’01/01/2002’, creditosp=2; Resultado: ERROR número no válido CLÁUSULA WHERE Si no se especifica ninguna condición, la sentencia causará la modificación de todas las filas de la tabla. Update profesores set ingreso=’01/01/2003’; resultado: 3 filas modificadas En el caso de que se indique alguna condición, se modificarán sólo aquellas filas de la tabla que cumplan la condición o condiciones impuestas. Así, la siguiente sentencia, a diferencia de la anterior que modifica todas las filas de la tabla profesores, hará que se modifique la fecha de ingreso sólo a aquellos profesores cuya categoría sea TEU. Update profesores set ingreso=’01/01/2003’ where categoria = ‘TEU’; resultado: 2 filas modificadas La condición indicada en la cláusula where puede ser tan complicada como se desee. Por ejemplo, la sentencia siguiente modifica los créditos de las asignaturas que son impartidas por profesores con categoría de TEU. Update asignaturas set creditos = 0 where codigo in (select asignatura from imparte i, profesores p where i.dni = p.dni and p.categoria=’TEU’); Resultado: 1 fila modificada MODIFICACIÓN DE MÁS DE UNA FILA Existe la posibilidad de modificar la información contenida en una tabla asignando como nuevo valor o valores, el resultado de una consulta. UPDATE nombreTabla [aliasTabla] SET { {columna=expresion|columna=subconsulta} | listaColumnas=subconsulta} [WHERE condición] El resultado de la consulta puede asignarse a una única columna o a una lista de columnas. En el primer caso, la sentencia SELECT sólo devolverá un valor (una fila y una columna) el cual debe coincidir en tipo de dato y longitud con el tipo de dato y longitud de la columna a la cual asignamos el valor. Update imparte set asignatura=’BDA’, dni = (select dni from profesores where categoria=’ASO6’) where asignatura like ‘%BD%’; resultado: 1 fila actualizada Si la restricción de que la consulta devuelva una fila y una columna no se cumple no se realiza la actulización. Update imparte set asignatura=’BDA’, 48 dni = (select dni from profesores) where asignatura like ‘%BD%’; resultado: ERROR la subconsulta devuelve más de una fila Update imparte set asignatura=’BDA’, dni = (select dni, nombre from profesores where categoria =’ASO6’) where asignatura like ‘%BD%’; resultado: ERROR demasiados valores La segunda opción asigna el resultado de una consulta a una lista de columnas. En este caso, la sentencia SELECT devolverá una única fila, pero con tantas columnas como elementos haya en la lista de columnas. Los valores se asignan por orden, de forma que a la primera columna se le asigna el valor de la primera columna de la SELECT, a la segunda la segunda, y así sucesivamente. En el ejemplo siguiente se seleccionan dos columnas para dar valor a las columnas dni y asignatura de la tabla impartir. Update imparte set (dni,asignatura) = (select dni, ‘BDA’ from profesores where categoria =’ASO6’) where asignatura like ‘%BD%’; resultado: 1 fila actualizada Update imparte set (dni,asignatura) = (select dni, ‘BDA’ from profesores) where asignatura like ‘%BD%’; resultado: ERROR la subconsulta devuelve más de una fila Update imparte set (dni,asignatura) = (select dni, ‘BDA’, nombre from profesores where categoria =’ASO6’) where asignatura like ‘%BD%’; resultado: ERROR demasiados valores Update imparte set (dni,asignatura) = (select dni from profesores where categoria =’ASO6’) where asignatura like ‘%BD%’; resultado: ERROR no hay suficientes valores Deberá existir una concordancia de tipo de dato y longitud entre los elementos de la lista de columnas y las columnas seleccionadas. CLAVES AJENAS: influencia en el UPDATE En general, las claves ajenas generan las mismas restricciones de integridad referencial que el DELETE salvo por la naturaleza de la operación: el UPDATE sólo generará problemas de integridad referencial si el dato a modificar es un valor de clave primaria que está siendo referenciada por alguna clave ajena. Suponiendo el estado de la base de datos original: Update asignaturas set codigo = BD1 where codigo = ‘FBD’; 49 resultado: ERROR:restricción de integridad (BDI.SYS_C005870012) violada registro secundario encontrado Para poder realizar esta operación, será necesario insertar una nueva fila en asignaturas con el identificador BD1 y copiando el resto de los valores, después cambiar las referencias a ‘FBD’ por ‘BD1’ y, por último, borrar la fila de ‘FBD’. Insert into asignaturas (codigo,descripcion,creditos,creditosp) select ‘BD1’, descripcion,creditos,creditosp from asignaturas where codigo = ‘FBD’; resultado: 1 fila insertada Update imparte set asignatura = ‘BD1’ where asignatura = ‘FBD’; Resultado: 1 fila suprimida Delete from asignaturas where codigo = ‘FBD’; Resultado: 1 fila suprimida ÓRDENES MANIPULACIÓN2 Los siguientes ejercicios se ejecutarán sobre la base de datos de Proveedores, ya conocida. Antes de comenzar, deberás ejecutar las instrucciones contenidas en el fichero BD1CreateBD.sql para la creación de la BD e inserción de datos iniciales. 1. Haz que la fecha de recuento del inventario de todas las piezas sea el 1 de enero de 2003. 2. Modifica la cantidad mínima de todas las piezas inventariadas que cumplan que la cantidad disponible es menor. Haz que tomen el valor de la cantidad disponible de cada una de ellas. 3. Para aquellos vendedores para los que no tengamos teléfono, ponles el valor ‘SIN TLFNO’. 4. Haz que la calle, la ciudad y la provincia de los vendedores de TOLEDO sea ‘CENTRAL, 5’,‘SALAMANCA’, ‘SALAMANCA’. 5. Modifica los datos de las piezas que no tengan descripción. Haz que tomen el valor ‘SIN DESCRIPCION’. 6. Las piezas suministradas por el vendedor de número 3 van a ser suministradas a partir de ahora por el de número 500, a un preciounitario de 5 euros. 7. Pon a 0 el descuento de las piezas cuyos días de suministro sea inferior a 3. 8. Para pedidos anteriores al año 2000, modifica el número de vendedor por el 3. 9. Modifica los pedidos realizados por el vendedor de número 200 de forma que los haya realizado el vendedor de número 1000. 10. El pedido con número 8 va a tener a partir de ahora el número 4, el pedido con número 5 va a tener a partir de ahora el pedido con número 1, el 8 será el 2 a partir de ahora y el 3 el 2. 12 Recuérdese que el identificador de restricción (en este caso, una clave ajena) lo asigna el sistema y puede cambiar de un usuario a otro. 50 11. Para los pedidos en los que la cantidad recibida variara de la pedida, haz que no sea así. 12. Actualiza la ciudad y la provincia de los vendedores que no sean de ALICANTE. Asígnales los valores de la ciudad y la provincia del vendedor de número 3. 13. Modifica la descripción de las piezas que estén SIN DESCRIPCIÓN asignándoles la descripción de la que tenga el precio de venta igual a 7 euros. 14. Actualiza el precio de venta de la pieza de número A-1001-L a 4 euros y el de la pieza de número C-1002-H a 15. 15. A partir de ahora el vendedor número 5 suministrará la pieza DISKETTE 1.44 PANASONIC al precio de venta de la misma. 16. Haz lo mismo que en el ejercicio anterior, pero para el vendedor de número 200. 17. Los pedidos del vendedor número 3 han sido realizados a fecha de hoy. 18. Pon el precio de compra igual al precio de venta, la cantidad pedida y recibida a 100 y la fecha de recepción a la fecha del día, para las líneas de pedido en las que la pieza pedida sea A-1001-L. 19. Modifica los datos de las piezas recontadas con anterioridad al 1 de enero de 2003 de forma que el período de recuento sea el mismo que para las piezas recontadas 51 52 manipulación 3 INTEGRIDAD REFERENCIAL Y BORRADOS Objetivos: • Extender la gestión de las claves ajenas y automatizar el borrado cuando produce problemas de integridad referencial. Contenidos • Cláusula ON DELETE (políticas de mantenimiento de la integridad referencial en las claves ajenas ante borrados en claves primarias) ON DELETE Ya se ha practicado con la integridad referencial en sesiones anteriores y se ha visto que el intento de borrar ciertas filas es rechazado por el SGBD si éstas están siendo referenciadas por alguna clave ajena. Recordemos la estructura y el contenido de la base de datos Ejemplo: PROFESORES ( dni : char(9), nombre : char(25), categoria : char(4), ingreso : date ) Clave primaria: dni ASIGNATURAS ( codigo : char(5), descripcion : char(40), creditos : decimal(3,1), creditosp : decimal(3,1) ) Clave primaria: codigo IMPARTE ( dni : char(9), asignatura : char(5) ) Clave primaria: (dni, asignatura) Clave ajena: dni → PROFESORES Clave ajena: asignatura → ASIGNATURAS Extensiones de Ejemplo: ASIGNATURAS codigo descripcion creditos creditosp HI FBD DGBD PC FP 4.5 6.0 6.0 6.0 9.0 HISTORIA DE LA INFORMATICA FUNDAMENTOS DE LAS BASES DE DATOS DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 1.5 3.0 1.5 4.5 53 IMPARTE PROFESORES dni nombre categoria ingreso dni asignatura 21111222 21222333 21333444 EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO TEU TEU ASO6 21111222 21111222 21333444 FBD DGBD PC 01/10/1993 16/06/1989 16/06/1992 No hay ningún problema en borrar cualquier fila de la tabla IMPARTE, no existen claves ajenas que les hagan referencia, pero tanto PROFESORES como ASIGNATURAS son referenciadas por las claves ajenas definidas en IMPARTE y según el estado de la BD ciertas filas pueden ser eliminadas y otras no. Por ejemplo, podemos eliminar “Historia de la Informática” puesto que ningún profesor la imparte, pero si intentamos eliminar “Fundamentos de las Bases de Datos” el sistema mostrará un error y no realizará la operación. Delete from asignaturas where codigo = ‘FBD’; resultado: ERROR:restricción de integridad (BDI.SYS_C0058700) violada - registro secundario encontrado En ciertos sistemas de información es posible redefinir las restricciones de clave ajena para que no se den estos mensajes de error. Ello es posible mediante la cláusula ON DELETE al crear una tabla: FOREIGN KEY (columna[,columna[, ...]]) REFERENCES tabla ON DELETE {CASCADE | SET NULL} La acción a realizar ante el borrado de una fila que está siendo referenciada por alguna clave ajena puede ser el propagar la operacion (ON DELETE CASCADE) o anular (ON DELETE SET NULL), dependiendo de la decisión del diseñador de la base de datos. PROPAGAR EL BORRADO Supongamos que la tabla IMPARTE de la BD Ejemplo tiene la siguiente definición: create table IMPARTE ( dni varchar2(10), asignatura char(5), primary key (dni, asignatura), foreign key (dni) references PROFESORES (dni), foreign key (asignatura) references ASIGNATURAS (codigo) ON DELETE CASCADE); El resultado del borrado anteriormente intentado sería ahora: Delete from asignaturas where codigo = ‘FBD’; resultado: 54 1 fila suprimida ASIGNATURAS codigo descripcion creditos creditosp HI DGBD PC FP 4.5 6.0 6.0 9.0 HISTORIA DE LA INFORMATICA DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 3.0 1.5 4.5 IMPARTE PROFESORES dni nombre categoria ingreso dni asignatura 21111222 21222333 21333444 EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO TEU TEU ASO6 21111222 21333444 DGBD PC 01/10/1993 16/06/1989 16/06/1992 Como ya hemos dicho, eliminar la asignatura Historia de la Informática no genera conflictos de integridad referencial por lo que el sistema puede hacerlo sin problemas: Delete from asignaturas where codigo = ‘HI’; resultado: 1 fila suprimida ASIGNATURAS codigo descripcion creditos creditosp DGBD PC FP 6.0 6.0 9.0 DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 3.0 1.5 4.5 IMPARTE PROFESORES dni nombre categoria ingreso dni asignatura 21111222 21222333 21333444 EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO TEU TEU ASO6 21111222 21333444 DGBD PC 01/10/1993 16/06/1989 16/06/1992 Sin embargo, nótese que la clave ajena dni que hace referencia a PROFESORES no tiene modificado su comportamiento ante borrados: Delete from profesores where dni = ‘21111222’; resultado: ERROR:restricción de integridad (BDI.SYS_xxxxx) violada - registro secundario encontrado Delete from profesores where dni = ‘21222333’; resultado: 1 fila borrada La fila de Eva GOMEZ no ha podido ser eliminada puesto que imparte DGBD (y no se ha modificado con ON DELETE) pero sí se ha borrado la de Manuel Palomar, que no imparte asignatura alguna. 55 ASIGNATURAS codigo descripcion creditos creditosp DGBD PC FP 6.0 6.0 9.0 DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 3.0 1.5 4.5 IMPARTE PROFESORES dni nombre categoria ingreso dni asignatura 21111222 21222333 EVA GOMEZ MANUEL PALOMAR TEU TEU 21111222 21333444 DGBD PC 01/10/1993 16/06/1989 ANULAR EL VALOR DE CLAVE AJENA Si la modificación de una clave ajena es ON DELETE SET NULL, la acción que llevará a cabo automáticamente el SGBD es la de poner NULOS en aquellos casos en que la integridad referencial se vea comprometida. Esta definición tiene más dificultad de aplicación puesto que prevalecen las definiciones de clave candidata. Por ejemplo, la siguiente definición es inútil puesto que dni en IMPARTE forma parte de la clave primaria y no admite nulos en ningún caso: create table IMPARTE ( dni varchar2(10), asignatura char(5), primary key (dni, asignatura), foreign key (dni) references PROFESORES (dni) ON DELETE SET NULL, foreign key (asignatura) references ASIGNATURAS (codigo) ); Delete from profesores where dni = ‘21111222’; resultado: ERROR: no se puede actualizar (“IMPARTE”.”DNI”) a un valor NULL El sistema ha intentado cambiar el valor ‘21111222’ en la tabla IMPARTE por un nulo pero, al ser parte de la clave primaria, ha rechazado la operación. Supongamos que la tabla imparte tiene esta otra definición: create table IMPARTE ( ficha integer, dni varchar2(10), asignatura char(5), primary key (ficha), foreign key (dni) references PROFESORES (dni) ON DELETE SET NULL, foreign key (asignatura) references ASIGNATURAS (codigo) ); Y el contenido de la BD es ahora: ASIGNATURAS codigo descripcion creditos creditosp HI FBD DGBD PC FP 4.5 6.0 6.0 6.0 9.0 56 HISTORIA DE LA INFORMATICA FUNDAMENTOS DE LAS BASES DE DATOS DISEÑO Y GESTION DE BASES DE DATOS PROGRAMACION CONCURRENTE FUNDAMENTOS DE LA PROGRAMACION 1.5 3.0 1.5 4.5 PROFESORES dni nombre categoria ingreso 21111222 21222333 21333444 EVA GOMEZ MANUEL PALOMAR RAFAEL ROMERO TEU TEU ASO6 01/10/1993 16/06/1989 16/06/1992 IMPARTE ficha dni asignatura 1 2 3 21111222 21111222 21333444 FBD DGBD PC Delete from profesores where dni = ‘21111222’; resultado: 1 fila borrada El sistema puede borrar la fila de la profesora Eva GOMEZ, poniendo nulos en cualquier referencia que halle en la clave ajena afectada de IMPARTE. PROFESORES dni nombre categoria ingreso 21222333 21333444 MANUEL PALOMAR RAFAEL ROMERO TEU ASO6 16/06/1989 16/06/1992 IMPARTE ficha 1 2 3 dni asignatura 21333444 FBD DGBD PC ON UPDATE ... En Oracle9 no existe la posibilidad de establecer políticas para el mantenimiento de la integridad referencial ante modificaciones (UPDATE) de valores de clave primaria. 57 ÓRDENES MANIPULACIÓN3 Los siguientes ejercicios se ejecutarán sobre la base de datos de Proveedores, ya conocida. Antes de comenzar, deberás ejecutar las instrucciones contenidas en el fichero BD1CreateBD2.sql para la creación de la BD e inserción de datos iniciales. Nótese que se han efectuado cambios en la definición de ciertas claves ajenas para incorporar las políticas de mantenimiento de la integridad referencial ante borrados: PRECIOSUM PEDIDO LINPED INVENTARIO Clave Clave Clave Clave Clave Clave Clave Clave Clave Clave Clave Primaria: (numpieza, numvend) Ajena: (numpieza)→ PIEZA RECHAZAR13 Ajena: (numvend)→ VENDEDOR PROPAGAR Primaria: (numpedido) Ajena: (numvend)→ VENDEDOR PROPAGAR Primaria: (numpedido, numlinea) Ajena: (numpedido)→ PEDIDO PROPAGAR Ajena: (numpieza)→ PIEZA ANULAR Primaria: (numbin) Alternativa: (numpieza) Ajena: (numpieza)→ PIEZA ANULAR Para la comprobación de los efectos de las siguientes órdenes es conveniente tener a mano la sesión Select 1 donde se muestra el contenido original de la BD PROVEEDORES. 1. Borra el vendedor 1. 2. Comprueba los efectos de la operación anterior consultando todas las tablas. 3. Borra el vendedor 3. 4. Comprueba los efectos de la operación anterior consultando todas las tablas. 5. Borra el vendedor 8001. 6. Comprueba los efectos de la operación anterior consultando todas las tablas. 7. Borra el pedido 6 8. Comprueba los efectos de la operación anterior consultando todas las tablas. 9. Borra la pieza O-0001-PP. 10. Borra todos los suministros de la pieza O-0001-PP. 11. Borra la pieza O-0001-PP. 12. Comprueba los efectos de la operación anterior consultando todas las tablas. 13. Borra todos los suministros de la pieza DD-0001-210. 14. Borra la pieza DD-0001-210. 15. Modifica BD1CreateBD2.sql (y ejecútalo después de realizada la modificación) cambiando la política de la clave ajena de INVENTARIO a PROPAGAR, y añádele una nueva tabla con los siguientes datos: NUEVA(orden entero) CP(orden) Card(NUEVA, rel1) = (0,1) Card(PRECIOSUM, rel1) = (0,N) RECHAZAR 16. Inserta en NUEVA los 3 suministros de la pieza T-0001-IBM. 17. Intenta borrar el vendedor 2 y localiza el error producido. 18. Modifica la política de la clave ajena de NUEVA a ANULAR (y ejecuta), vuelve a insertar los suministros del ejercicio 16, y vuelve a borrar el vendedor 2, comprobando los efectos sobre la BD. 13 “Ante borrados en PIEZA, rechazar la operación si existen referencias”, y así con todas las claves ajenas definidas. 58 conjuntos OPERACIONES DE CONJUNTOS Objetivos: • Combinar el resultado de varias sentencias select en un único resultado, utilizando los operadores de conjuntos: unión, intersección y diferencia. Contenidos • Union, Union All • Intersect • Minus • Resolución de requerimientos. OPERADORES SOBRE CONJUNTOS Un operador sobre conjuntos combina el resultado de dos sentencias SELECT en un único resultado. Para que se pueda realizar, las sentencias SELECT deben tener ambas como resultado el mismo número de columnas y los mismos tipos de datos (no es necesario que sean de igual longitud). Los operadores de conjuntos son la UNION, UNION ALL, INTERSECT y MINUS. En la versión de Oracle con la que trabajamos, todos tienen la misma precedencia y se evalúan de izquierda a derecha. Si queremos alterar este orden debemos utilizar los paréntesis. UNION, UNION ALL Al utilizar el operador UNION entre dos sentencias SELECT, el resultado final estará compuesto por todas aquellas filas que aparecen en el resultado de como mínimo una de las SELECT. El operador UNION elimina filas duplicadas en el resultado final. El operador UNION ALL opera de igual modo que el operador UNION, pero no elimina filas duplicadas en el resultado final. Supongamos que queremos saber el nombre de los profesores que son ASO6 o imparten asignaturas de 6 créditos. Se calcula cada SELECT por separado. select nombre from profesores where categoria=’ASO6’ resultado: nombre RAFAEL ROMERO 59 select nombre from profesores p, imparte i, asignaturas where p.dni=i.dni and asignatura=codigo and creditos=6 resultado: nombre RAFAEL ROMERO EVA GOMEZ EVA GOMEZ En el resultado final aparecerán todas las filas que estén en cualquiera de los dos resultados. select nombre from profesores where categoria=’ASO6’ UNION select nombre from profesores p, imparte i, asignaturas where p.dni=i.dni and asignatura=codigo and creditos=6 resultado con UNION ALL: nombre RAFAEL ROMERO RAFAEL ROMERO EVA GOMEZ EVA GOMEZ con UNION nombre RAFAEL ROMERO EVA GOMEZ INTERSECT Al utilizar el operador INTERSECT entre dos sentencias SELECT, el resultado final estará compuesto por todas aquellas filas que aparezcan en los resultados de ambas sentencias (no es suficiente que aparezcan sólo en el resultado de una de ellas) Supongamos que queremos saber el nombre de los profesores que son ASO6 e imparten asignaturas de 6 créditos. select nombre from profesores where categoria=’ASO6’ INTERSECT select nombre from profesores p, imparte i, asignaturas where p.dni=i.dni and asignatura=codigo and creditos=6 resultado: nombre RAFAEL ROMERO Se calcula cada SELECT por separado y aparecen en el resultado final todas las filas que estén en ambos resultados. MINUS Al utilizar el operador MINUS entre dos sentencias SELECT, el resultado final estará compuesto sólo por aquellas filas que aparecen en el resultado de la primera SELECT y no aparecen en el resultado de la segunda. Supongamos que queremos saber el nombre de los profesores que son ASO6 y no imparten asignaturas de 6 créditos. 60 select nombre from profesores where categoria=’ASO6’ MINUS select nombre from profesores p, imparte i, asignaturas where p.dni=i.dni and asignatura=codigo and creditos=6 resultado: nombre Supongamos que las condiciones hubiesen estado al revés. Queremos saber el nombre de los profesores que imparten asignaturas de 6 créditos y no son ASO6. select nombre from profesores p, imparte i, asignaturas where p.dni=i.dni and asignatura=codigo and creditos=6 MINUS select nombre from profesores where categoria=’ASO6’ resultado: nombre EVA GOMEZ Algunos de estos requerimientos se pueden resolver con una sola sentencia SELECT donde se combinen de modo adecuado las condiciones. En otras ocasiones debemos recurrir a operar con los resultados de varias sentencias. Por ejemplo, en estos dos últimos enunciados, el segundo se puede solucionar con una SELECT, mientras que en el caso del primero es necesario trabajar con dos. CONSULTAS CONJUNTOS 1. Nombre de las empresas que tienen vendedores con pedidos O que puedan suministrar la pieza ‘A-1001-L’. 2. Nombre de las empresas que tienen vendedores con pedidos Y que puedan suministrar la pieza ‘A-1001-L’. 3. Nombre de las empresas que tienen vendedores con pedidos PERO NO suministran la pieza ‘A-1001-L’. 4. Número de los pedidos en los que se soliciten teclados pero no monitores. 5. Número y nombre de las piezas que suministra el vendedor número 1, vendedor número 2. 6. Número y nombre de las piezas con un precio de venta mayor que 1000, y todas las que pueden ser suministradas por el vendedor número 1, ordenado por nombre. 7. Número y nombre de las piezas que han sido pedidas pero no inventariadas 8. Número y nombre de los vendedores de la empresa MECEMSA que, además, tienen suministros de precio unitario mayor que 10 o se les ha hecho algún pedido pero no el 61 62 funciones ARITMÉTICA Y FUNCIONES AGREGADAS Objetivos: • Obtención de información calculada. Contenidos • operaciones aritméticas: +, -, *, / • SUM(), AVG(), COUNT(), MAX(), MIN(), ROUND(), ABS(). • etiquetas para columnas • Resolución de requerimientos. Introducción de las funciones estadísticas aplicables a columnas enteras y de cuenta de filas, así como la forma de realizar operaciones como suma, producto, etc., de valores escalares. OPERACIONES ARITMÉTICAS Se pueden utilizar expresiones aritméticas tanto en la cláusula select, para obtener una nueva columna en la tabla resultado, como en la construcción de condiciones de selección de filas. Número de horas semanales, en un sólo semestre, que se imparten de cada asignatura: select descripcion, (creditos/3)*2 from asignaturas resultado: descripcion Historia de la Informática Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente Fundamentos de Programación (creditos/3)*2 3 4 4 4 6 63 Descripción de las asignaturas y número de horas semanales de las asignaturas con menos de 4 horas semanales de clase: select descripcion, creditos from asignaturas where (creditos/3)*2 < 4 resultado: descripcion Historia de la Informática creditos 4.5 FUNCIONES AGREGADAS Se dispone de una serie de funciones agregadas que retornan valores calculados sobre una determinada columna. Estas funciones devuelven un único valor para todas las tuplas seleccionadas mediante la condición de la cláusula where; si no se especifica ésta, el cálculo se realiza sobre la totalidad de la columna. COUNT( * COUNT( DISTINCT expr SUM( [DISTINCT] expr AVG( [DISTINCT] expr MIN( expr MAX( expr ROUND( expr ABS( expr ) ) ) ) ) ) ) ) número de filas número de valores distintos en la columna expr suma de todos los valores en expr promedio de todos los valores en expr el más pequeño de todos los valores en expr el mayor de todos los valores en expr redondea expr valor absoluto de expr Las funciones de tipo estadístico precisan que la expresión que se evalúe se construya sobre columnas de tipo de datos numérico. La expresión expr puede contener el nombre de una columna o un cálculo sobre una o varias columnas. Si se especifica la palabra clave distinct la expresión obligatoriamente ha de ser un nombre de columna, y se asume que la función se calcula únicamente sobre valores distintos de la expresión. En ningún caso se pueden anidar funciones: avg ( min ( creditos ) ) no está permitido. ¿Cuántos profesores hay en nuestra BD? select count( * ) from profesores resultado: ( count( * ) ) 3 ¿Cuántas asignaturas de más de 5 créditos hay en nuestra BD? select count( * ) from asignaturas where creditos > 5 resultado: ( count( * ) ) 4 ¿Cuántas valores de créditos distintos hay en nuestra BD? select count( distinct creditos ) from asignaturas resultado: ( count ) 3 64 ¿Cuál es la media de créditos por asignatura? select avg( creditos ) from asignaturas resultado: ( avg ) 6.3 ¿Cuál es la media de horas por asignatura? select avg( creditos*2/3 ) from asignaturas resultado: ( avg ) 4.2 Total de créditos ofertados en asignaturas de Bases de Datos: select sum( creditos ) from asignaturas where codigo like '%BD' resultado: sum( creditos ) 12 ETIQUETAS PARA COLUMNAS Dado que las expresiones calculadas no tienen un nombre específico de columna en la salida por pantalla, es conveniente "renombrarlas" para aclarar su significado. Se pueden etiquetar las columnas de la tabla resultado añadiendo, antes de la coma si hubiera más columnas detrás, una cadena de no más de 18 caracteres y sin espacios en blanco, tal como se hace con los alias temporales de las tablas. Esta cadena de caracteres aparecerá en el encabezado de la columna. select count( * ) num_asignaturas, avg(creditos) mediactos from asignaturas resultado: num_asignaturas mediactos 5 6.30 65 CONSULTAS FUNCIONES 1. Obtener la diferencia entre cantidad pedida y cantidad recibida de las líneas del pedido 1. 2. Media de días de intervalo entre la fecha de envío del pedido 1 y de entrega de las distintas piezas solicitadas en ese pedido 3. Obtener la cantidad de provincias distintas de las que tenemos conocimiento de algún proveedor. 4. Mínima diferencia entre precio de compra y precio de suministro del vendedor al que se le compró. 5. Media de precios distintos de venta de piezas. 6. Máximo descuento (en euros) de las piezas suministradas. 7. Número, nombre y diferencia entre precio de venta y precio de compra de la(s) pieza(s) que suministran los vendedores de Alicante. 8. Máximo, mínimo y media de precio de venta de las piezas. 9. Cantidad total de piezas que sabemos nos pueden suministrar los proveedores. 10. Cantidad de vendedores de nuestra BD. 11. Total de la diferencia en euros entre lo pagado por compra de artículos y sus respectivos precios de suministro ofrecidos en su día por los proveedores si el segundo precio es menor que el primero. 66 group by INFORMACIÓN AGRUPADA Objetivos: • Obtención de información calculada sobre grupos de filas. Contenidos • GROUP BY • Resolución de requerimientos. Clasificación de información en función de algún criterio especificado mediante la cláusula GROUP BY. LA CLÁUSULA GROUP BY Supongamos que queremos obtener la cantidad de asignaturas que imparte cada profesor: select p.dni, nombre, count( * ) from profesores p, imparte i where p.dni = i.dni group by p.dni, nombre resultado: dni 21111222 21333444 nombre EVA GOMEZ RAFAEL ROMERO ( count ) 2 1 En esta ocasión, y por la utilización de la cláusula group by, la cuenta de valores distintos de la columna asignatura se calcula en base a cada profesor de nuestra BD que imparte alguna asignatura. El criterio de agrupación se forma con al menos todas las columnas no calculadas de la lista de la cláusula select. • No se pueden poner columnas no calculadas en la select que no aparezcan en la group by. select p.dni, nombre, count( * ) from profesores p, imparte i where p.dni = i.dni group by p.dni resultado: ERROR 67 • Si se pueden poner más columnas en la lista del group by que en la de la select. select nombre, count( * ) from profesores p, imparte i where p.dni = imparte.dni group by p.dni, nombre resultado: nombre ( count(*) ) EVA GOMEZ RAFAEL ROMERO 2 1 where y group by Cuando se utiliza la cláusula where, aparte de enlazar tablas por columnas comunes, como PROFESORES e IMPARTE por profesores.dni e imparte.dni respectivamente, se puede utilizar para eliminar ciertas filas del cálculo. Así, si queremos calcular cuantas asignaturas imparte cada profesor sin contar Fundamentos de las Bases de Datos, escribiremos la siguiente sentencia. select nombre, count( * ) from profesores p, imparte i where p.dni = i.dni and asignatura <> 'FBD' group by p.dni, nombre resultado: nombre EVA GOMEZ RAFAEL ROMERO ( count(*) ) 1 1 ATRIBUTOS NO CLAVE EN EL GROUP BY Los únicos atributos que aseguran la identificación de una tupla respecto de las demás son los que forman la clave primaria (en general, la clave candidata). Así, si la clave primaria de una tabla de personas (profesores o alumnos, por ejemplo) es el D.N.I., podemos decir sin equivocarnos que no habrá duplicados en este atributo. No obstante, el nombre no será clave y, por lo tanto, admite duplicados. Es decir, es perfectamente posible encontrar a dos personas distintas (con números de D.N.I. diferentes, obviamente) que se llamen igual (nombres y apellidos). Si, por ejemplo, agrupamos datos por el nombre y no por el D.N.I. podemos obtener información en una única fila de dos personas diferentes que se llaman igual. Sea una ocurrencia tal como ésta: DNI 21 22 68 CLIENTE NOMBRE JUAN JUAN OPERACIÓN 1 2 3 INGRESO CLIENTE 21 22 22 INGRESO 1000 2000 3000 select nombre, avg( ingreso ) media from cliente, ingreso where dni = cliente group by nombre resultado: nombre JUAN media 2000 Puesto que el nombre es el mismo para los dos clientes, la agrupación contabiliza todas las ocurrencias de ingreso como de uno sólo. Sin embargo, si introducimos en la lista de columnas del GROUP BY aquellas que son su clave primaria: select nombre, avg( ingreso ) media from cliente, ingreso where dni = cliente group by dni, nombre resultado: nombre JUAN JUAN media 1000 2500 Es evidente que, si queremos saber exactamente de a qué cliente nos referimos en cada tupla del resultado, debemos incluir la clave primaria como atributo de la relación derivada de la ejecución de la select. En general, y aunque no afecte al resultado, evitaremos la no inclusión de atributos clave en la cláusula group by. ORDENACIÓN DE LA SALIDA En la cláusula order by podemos especificar la expresión tal cual aparece en la select. select dni, count( * ) asignaturas from profesores group by p.dni, nombre order by count( * ) resultado: dni 21333444 21111222 asignaturas 1 2 O bien podemos utilizar una alias para la columna (asignaturas en este ejemplo) o el orden de la columna empezando por la izquierda (la función está en la tercera columna en este ejemplo): select dni, count( * ) asignaturas from profesores group by p.dni, nombre order by asignaturas select dni, count( * ) asignaturas from profesores group by p.dni, nombre order by 2 resultado: dni 21333444 21111222 asignaturas 1 2 69 CONSULTAS GROUP BY NOTA: es muy recomendable, aunque no se especifique explícitamente en el requerimiento, que la salida se ordene ascendentemente (por defecto) por las columnas no calculadas de la lista de la cláusula select. NOTA: así mismo, se deben etiquetar las columnas calculadas. 1. Obtener para cada pieza, nombre de la pieza, precio de venta, y la media de la diferencia entre el precio de venta y el de suministro. 2. Obtener para cada número de pedido, el precio pagado en total por ese pedido, la cantidad pedida total así como la diferencia entre cantidad pedida total y cantidad recibida total. 3. Obtener la cantidad de vendedores de cada empresa, indicando cantidad y nombre de la misma, ordenado descendentemente por cantidad de empleados. 4. Obtener, por pieza solicitada, la máxima diferencia entre cantidad pedida y cantidad recibida de entre todas las veces en que fue servida. 5. Obtener para cada pieza, el número de la pieza y el número total de vendedores que nos pueden suministrar esa pieza. 6. Obtener número de pieza y número total de vendedores que la pueden suministrar para piezas de más de 250 de precio de venta. 7. De cada pieza obtener el precio unitario medio de suministro. 8. De cada pieza de precio de venta mayor que 250 obtener el precio medio de suministro. 9. Obtener la media de las ventas (en euros) realizadas por cada vendedor de cada pieza. 10. Obtener la cantidad de pedidos efectuados por fecha y el total pagado por las mercancías. 11. Calcular las ganancias (precio de compra menos precio de suministro por la cantidad recibida) de cada vendedor que ha efectuado alguna venta. 12. Calcular por número de pedido, la media de la diferencia entre el precio de compra y el de suministro (que nos ofertaba el vendedor al que se le solicitó el pedido) de las líneas de cada pedido. 13. Calcular para cada pieza, el tanto por ciento de beneficios del precio de venta al público respecto al precio medio de compra de todas las compras que se han realizado de la pieza 14. Obtener, por cada pieza solicitada, cuántos vendedores la podrían suministrar, ordenado alfabéticamente por la descripción de la pieza y eliminando aquellas compradas a proveedores de Alicante. 70 group by - having SELECCIÓN DE INFORMACIÓN AGRUPADA Objetivos: • Establecer selecciones sobre información agrupada. Contenidos • HAVING. • Resolución de requerimientos. LA CLÁUSULA HAVING Al igual que la cláusula where selecciona filas, la cláusula having selecciona grupos; si en la where la condición que se especifica afecta a las tuplas de toda la tabla, el group by efectúa los cálculos en función de esa selección previa y da como resultado una tabla con la información calculada para cada grupo. Sobre esta última el having eliminaría aquellas tuplas que no cumplen la condición. Normalmente, where selecciona sobre los datos almacenados en la tabla y having sobre la información calculada. Supongamos que queremos saber cuantas asignaturas imparte cada profesor pero únicamente en el caso de que imparta 2 ó más asignaturas: select p.dni, nombre, count( * ) asignaturas from profesores p, imparte i where p.dni = i.dni group by p.dni, nombre having count(*) >= 2 order by nombre resultado: dni 21111222 nombre EVA GOMEZ asignaturas 2 71 select p.dni, nombre, count( * ) asignaturas from profesores p, imparte i where p.dni = i.dni and asignatura <> 'FBD' group by p.dni, nombre having count(*) >= 2 order by nombre resultado: dni nombre asignaturas En la expresión del having no se pueden utilizar los alias de las columnas (asignaturas) en este caso. Veamos, cláusula a cláusula, los efectos de esta última orden: 1. la cláusula where ha eliminado las tuplas de imparte de código de asignatura FBD. 2. la cláusula group by calcula, para cada profesor, el número de asignaturas que imparte. Puesto que no contamos FBD, Eva GOMEZ sólo imparte, igual que Rafael Romero, una única asignatura. 3. la cláusula having elimina del resultado del paso anterior todas aquellas tuplas con un valor en la cuenta de filas menor que 2. El resultado es vacío puesto que ninguno de los grupos supera la condición. CONSULTAS GROUP BY - HAVING 1. Nombre de las empresas que tienen más de dos vendedores. 2. Números de pedido que tengan más de tres líneas de pedido. 3. Números de pedido donde el total de piezas pedidas es mayor que 40. 4. Obtener los números de pedido donde el precio total sea superior a 1000. 5. Para las piezas que se hayan ofertadoa un precio unitario medio mayor que 260 obtener el número de pieza, el máximo precio unitario, y la cantidad de suministradores. 6. Para las piezas que se ofrecen a un precio unitario medio mayor que 260 (sin tener en cuenta los suministros menores de 250) obtener el número de pieza, el máximo precio unitario, y la cantidad de suministradores. 7. Obtener aquellos números de pedido y fecha en que se confeccionaron cuya cantidad de artículos pedidos sea superior a 30 y la recibida inferior a 10. 8. Obtener el número de pieza y el precio unitario medio de aquellas piezas que tarden de media 14 días como máximo en ser suministradas (diassum=tiempo de suministro). 9. Obtener los números de pedido, precio de compra y cantidad pedida de los números de línea 1 y recibidas en fecha 10-05-92. 10. Obtener el número, el nombre y el precio máximo unitario de las piezas cuyo precio de venta sea mayor que 250 o menor que 170, su descuento medio oscile entre 10 y 17 y que tengan un precio unitario medio total superior a 150, ordenado por precio máximo. 11. Determinar el número total de proveedores que pueden suministrar la pieza 'P-0001-33’. 12. Para cada pieza, de la que se tiene información sobre sus posibles vendedores, obtener el número de pieza, y sus precios unitarios máximo y mínimo, exceptuando la información referida al vendedor número 1. 72 13. Dar una relación del nombre de las piezas que nos pueden suministrar más de dos proveedores. 14. Obtener el número y el nombre del vendedor así como el número y nombre de las piezas de precio unitario mayor que 200 que nos puedan suministrar. El resultado se dará ordenado por número y nombre de vendedor y por nombre de la pieza. 73 74 subselect CONSULTAS ANIDADAS Objetivos: • Utilizar el resultado de una sentencia select para establecer las condiciones de otra sentencia select. Contenidos • Subqueries. • operadores de comparación escalar. • IN, ALL, ANY, [NOT]. • Resolución de requerimientos. CONSULTAS ANIDADAS (SUBQUERIES) En la condición de búsqueda de la orden select (en la cláusula where o en la having) también podemos: • comparar una expresión con el resultado de otra orden select • determinar si el valor de una expresión está incluido en los resultados de otra orden select • preguntar si una orden select ha seleccionado filas. Cuando una orden select se encuentra dentro de la cláusula where de otra select recibe el nombre de subconsulta (subquery). Por ejemplo : select descripcion, creditos from asignaturas where creditos = ( select min(creditos) from asignaturas ) resultado: descripcion Historia de la Informática creditos 4.5 En primer lugar se calcula la select anidada (entre paréntesis) y se obtiene el valor mínimo para la columna créditos de la tabla asignaturas. Con ese valor se compara tupla a tupla y se obtiene la asignatura (o asignaturas) cuya cantidad de créditos es igual al mínimo. sintaxis general de la subconsulta expresión op_comparación { ALL | [ ANY | SOME ] } ( orden select ) expresión [ NOT ] IN ( orden select ) [ NOT ] EXISTS ( orden select ) Los valores posibles a devolver por una orden select anidada son : • nada • un valor único (una fila y una columna), • un conjunto de valores (varias filas y una columna). 75 Siempre que la subselect devuelva algo, únicamente será en una y nada más que una columna (salvo el operador EXISTS). DEVOLUCIÓN DE UN ÚNICO VALOR expresión op_comparación ( orden select ) Podemos utilizar los operadores de comparación para preguntar si el valor de una determinada expresión es mayor, menor, igual, etc. que el resultado de la subselect, siempre y cuando ésta devuelva una única fila y una única columna, es decir, un valor simple. En general serán órdenes select que calculan una función agregada (sum, min, max, avg, count). select descripcion from asignaturas where creditos = ( select min(creditos) from asignaturas ) No sería correcto, porque la subselect devuelve más de una fila, la siguiente orden : select descripcion from asignaturas where creditos = ( select creditos from asignaturas where creditos < 9 ) DEVOLUCIÓN DE UNA LISTA DE VALORES expresión op_comparación ALL | [ ANY | SOME ] ( orden select ) Cuando la tabla resultado contiene más de una fila (pero una única columna, insistimos) hay que utilizar un modificador para el operador de comparación. Nombre de la asignatura que tiene el mínimo número de créditos (es equivalente al primer ejemplo) : select descripcion from asignaturas where creditos <= ALL ( select creditos from asignaturas ) resultado: descripcion Historia de la Informática creditos 4.5 En este caso, el número en créditos de la asignatura tiene que ser menor o igual que todos (all) los valores obtenidos en la subconsulta (que es la relación de créditos de todas las asignaturas). 76 Nombre de las asignaturas que no tienen el mínimo número de créditos : select descripcion from asignaturas where creditos > ANY ( select creditos from asignaturas ) resultado: creditos 6 6 6 9 descripcion Fundamentos de las Bases de Datos Diseño y Gestión de Bases de Datos Programación Concurrente Fundamentos de la Programación Serían todas aquellas asignaturas cuyos créditos superasen al menos a uno (any) de los valores devueltos por la subconsulta. El modificador some es equivalente a any. Otra forma de expresar el mismo requerimiento : select descripcion from asignaturas where creditos != ( select min(creditos) from asignaturas ) Supongamos que deseamos obtener el nombre de los profesores que imparten una asignatura que no sea la máxima en número de créditos : select nombre from profesores p, asignaturas a, imparte i where p.dni = i.dni and i.asignatura = a.codigo and creditos < ANY ( select creditos from asignaturas ) resultado: nombre Eva GOMEZ Rafael Romero expresión [ NOT ] IN ( orden select ) También podemos consultar la pertenencia de un valor a la lista de valores devuelta por la subconsulta. Obtener todos los datos de los profesores que imparte alguna asignatura : select * from profesores where dni IN ( select dni from imparte ) O dicho de otra manera : datos de los profesores cuyo dni aparece en la tabla imparte. En este caso daría lo mismo procesar la orden : select p.* from profesores p, imparte i where p.dni = i.dni Se verá más clara la utilidad de este operador si preguntamos justo lo contrario. 77 Obtener todos los datos de los profesores que no imparten asignaturas : select * from profesores where dni NOT IN ( select dni from imparte ) Por último, veamos que algunos de estos operadores son equivalentes : expresión IN (orden select) expresión NOT IN (orden select) ≡ ≡ expresión =ANY (orden select) expresión !=ALL (orden select) CONSULTAS SUBSELECT 1. Obtener todos los datos de los vendedores a los que se les han solicitado más pedidos que a todos los demás. 2. Número y nombre de los vendedores que no ofertan ninguna pieza. 3. Número y nombre de los vendedores a los que se les ha solicitado algún pedido. 4. Número y nombre de los vendedores a los que no se les ha solicitado pedidos. 5. Nombre de la empresa que ofrece la pieza más barata de precio de suministro. 6. Número y descripción de la pieza más cara (precio de venta). 7. Para cada pieza que se ofrece en la lista de suministros, obtener el número de pieza, y sus precios unitarios máximo y mínimo, exceptuando aquellos suministrados por el vendedor número 1. 8. Número de pedido y precio total pagado del pedido más caro. 9. Número y nombre del vendedor al que se le ha solicitado el pedido más caro. 10. Número, descripción y precio de venta de los monitores que no han sido nunca solicitados. 11. Calcular, por cada número de vendedor, la cantidad de piezas distintas que ha vendido, para aquellos vendedores pertenecientes a la empresa con más proveedores. 12. Nombre de los suministradores que pueden suministrar al menos alguna de las piezas que puede suministrar el vendedor número 5. 13. Listar los vendedores que sean de la misma provincia que el vendedor número 100. 14. Obtener los nombres de los vendedores de la misma empresa que Luis García. 15. Número y descripción de las piezas cuyo precio medio de suministro esté por encima del mayor precio de compra pagado por ella. 16. Número, nombre, empresa en la que trabaja y número de piezas que puede suministrar el vendedor que tiene la media más alta de piezas servidas. 17. Nombre de la empresa con mayor importe de ventas. 18. Número y descripción de la pieza que ha sido pedida más veces. 19. Número y descripción de las piezas que pueden ser suministradas por proveedores de la Comunidad Valenciana o que pueden ser suministradas por el vendedor que ha realizado la menor venta (pedido de importe más bajo) 78 20. Número de vendedor, número de pieza y descuento para aquellas piezas cuyo precio de venta supere en más del 15% la media del precio de compra de los pedidos en los que aparece. 21. Cantidad de piezas a la venta de las que no tenemos información sobre sus posibles suministradores. 79 80 subselect - exists CONSULTAS ANIDADAS II Contenidos • El operador EXISTS. • Resolución de requerimientos. EL OPERADOR EXISTS [ NOT ] EXISTS ( orden select ) El operador exists nos informa si una subconsulta ha devuelto algún resultado, o lo que es lo mismo, si la tabla resultado tiene alguna fila. Exists devuelve verdadero si hay al menos una tupla en la relación derivada y falso si la relación derivada es vacía. Supongamos que queremos conocer si algún profesor imparte todas las asignaturas : select nombre from profesores p where not exists ( select codigo from asignaturas a where not exists ( select asignatura from imparte i where i.asignatura=a.codigo and p.dni=i.dni ) ) Vamos a leer el requerimiento siguiendo las apariciones del operador exists dentro de las sucesivas órdenes select : Nombre de los profesores tales que no hay ninguna asignatura que no imparta él. Supongamos que la forma que tiene el SGBD de resolver esta sentencia es la siguiente : • En la primera select recorremos la tabla de profesores. • Para cada profesor, la segunda select recorre la tabla de asignaturas. • Para cada profesor y asignatura comprueba que el primero imparte la segunda. Una vez que ha fijado el profesor y la asignatura, la última subconsulta dará como resultado verdadero si la imparte y falso en caso contrario (devolverá una tupla o no devolverá nada). Supongamos un profesor que no imparte al menos una de las asignaturas de nuestra base de datos. Cuando el SGBD esté resolviendo la última subselect para ese profesor y esa asignatura, como no están relacionados, no devolverá ninguna tupla : el resultado del segundo exists es falso, y, como está negado, finalmente verdadero (ese profesor no imparte esa asignatura). Por lo tanto, para la primera subselect, ya existe una asignatura que obtiene en la cláusula where un valor verdadero : esa asignatura saldrá en la tabla resultado. Como ésta última tiene al menos una fila, el primer exists será verdadero, y, como está negado, finalmente falso. El profesor no imparte todas las asignaturas de nuestra base de datos. Un profesor que imparta todas las asignaturas obtendrá siempre una fila en la última subselect y, por lo tanto, ninguna asignatura aparecerá como resultado de la primera subselect, el correspondiente exists será falso, y por efecto del operador de negación la condición será cierta : ese profesor aparecerá en la solución. En nuestra base de datos Ejemplo no hay ningún profesor que imparta todas las asignaturas. 81 Aunque puede inducir a error, por su traducción intuitiva del inglés al español, no se deben confundir nunca los operadores IN y EXISTS : el primero devuelve una lista de valores, mientras que el segundo devuelve un valor de verdad; la sintaxis también es muy diferente. CONSULTAS SUBSELECT - EXISTS 1. Nombre de los vendedores que pueden suministrar todas las piezas. 2. Nombre de los vendedores que no pueden suministrar ninguna pieza, ordenados alfabéticamente. 3. Numero y descripción de las piezas que se han solicitado en todos los pedidos del vendedor 1. 4. Nombre de las empresas que cumplen que todos sus vendedores son de la Comunidad Valenciana, ordenadas alfabéticamente. 5. Número y nombre de todos los vendedores de la ciudad de Alicante. 6. Empresas que no han servido ninguna pieza. 7. Empresas que han servido la(s) pieza(s) de mayor precio de venta. 8. Numero de los pedidos cuyas piezas tienen todas un precio de venta mayor que la mitad del precio máximo de venta. 9. Obtener todos los datos de los vendedores que sirvieron los pedidos del requerimiento anterior. 10. Número y nombre de los vendedores que han servido algún pedido (utilizando obligatoriamente EXISTS). 11. Número y nombre de la pieza de menor precio de suministro (utilizando EXISTS). 12. Nombre de los vendedores a los que se les haya solicitado más de dos pedidos (utilizando subconsultas). 13. Número de pedido, fecha y número de vendedor del pedido más caro (utilizando subconsultas). 82 adicionales 1 EJERCICIOS ADICIONALES CONSULTAS 1. Toda la información de las piezas que puedan ser suministradas por vendedores de empresas cuyo nombre empieza por 'H'. 2. Piezas que el vendedor numero 1 ofrece en la lista de suministros y que han sido servidas en algún pedido 3. Vendedores que pueden suministrarnos piezas que se venden al público con un precio de venta entre 50 y 100 y que esa pieza ha sido solicitada en algún momento (no necesariamente a ellos) 4. Nombre de las empresas de Alicante a las que se ha comprado algún monitor 5. Nombre y numero de las piezas que se han solicitado en algún pedido ordenadas por el nombre 6. Para cada pieza comprada, número de pieza y diferencia en euros entre el precio de compra y el de suministro del vendedor al que se le compró, ordenado descendentemente por dicha cantidad. 7. Numero de vendedor y empresa para la que trabaja de aquellos que han vendido alguna pieza por un precio mayor que el estipulado por ellos en la lista de suministros 83 84 adicionales 2 EJERCICIOS ADICIONALES CONSULTAS 1. Obtener el nombre de los vendedores y la cantidad de piezas que pueden suministrar, ordenado alfabéticamente por vendedor. 2. Obtener el número y el nombre de los vendedores y la cantidad de piezas que pueden suministrar ordenado alfabéticamente por vendedor. 3. Obtener el nombre de las piezas, la media del precio unitario de cada pieza y el precio de venta de todas las piezas de las que conocemos posibles suministradores. 4. Para cada pedido obtener el número de líneas que tiene, el número y nombre del vendedor y la fecha del pedido. 5. Obtener el nombre de las piezas, la media del precio unitario de cada pieza y el precio de venta de todas las piezas que puedan sernos suministradas por más de tres proveedores. 6. Obtener los números y nombres de los vendedores que han servido algún pedido con más de tres artículos diferentes. 7. Obtener número y nombre de vendedores a los que les hayamos solicitado algún pedido. 8. Obtener el nombre de las piezas, la media del precio unitario de cada pieza y el precio de venta de todas las piezas de precio unitario medio mayor que 100 y que puedan ser suministradas por más de dos proveedores. 9. Obtener para cada pieza, el nombre de las pieza, la media del precio unitario de suministro y el precio de venta, para las piezas de precio de venta mayor que 300, teniendo en cuenta que la media de los precios unitarios debe estar entre 100 y 280. Ordenar el resultado por el nombre de la pieza. 10. Obtener número y nombre de las piezas que tengan una diferencia entre precio de venta y media de precio de suministro (preciounit) menor del 20% del precio de venta. 85 86 adicionales 3 EJERCICIOS ADICIONALES CONSULTAS 1. Obtener para los vendedores de la provincia de Alicante, el número de vendedor, su nombre y la cantidad total de pedidos que se les ha solicitado. 2. Obtener la cantidad total de piezas que se solicitaron en el año 1992. 3. Obtener el número de pedido, el importe total, y el numero y nombre del vendedor al que se les solicitó, para los pedidos de importe total superior a 10000 euros. Ordena el resultado por el importe total. 4. Para cada pieza que pueda ser suministrada a un precio medio unitario inferior a 10 euros, obtener el número de la pieza, su nombre, el precio máximo al que nos la han ofrecido, el precio mínimo y la cantidad de vendedores que nos la pueden suministrar. 5. Para los pedidos que nos han sido servidos en más de un día, obtener el número de pedido, el número del vendedor al que se le solicitó, su nombre, y la cantidad de días distintos en los que nos han servido las piezas solicitadas. 6. Para las empresas que tengan un único vendedor, obtener el nombre de la empresa y la cantidad total de pedidos que se le han solicitado, y el importe total entre todos los pedidos. 7. Para las piezas recibidas en domingo, obtener el número de la pieza, su nombre y el número y nombre del vendedor al que se le solicitaron. Ordena el resultado por el nombre de la pieza. 87 88 adicionales 4 EJERCICIOS ADICIONALES CONSULTAS 1. Número y nombre de los vendedores a los que les hemos solicitado algún pedido en el año 1995 pero no les hemos solicitado ninguno en el año 1992. 2. Obtener el número y el nombre las piezas que puedan sernos suministradas por más de dos vendedores de la provincia de Alicante, y que en total (entre todos los pedidos solicitados a todos los vendedores) hayamos pedido más de 500 unidades. 3. Obtener el nombre de las empresas de las que tengamos más de 1 de un vendedor de Alicante y no se les haya hecho ningún pedido (a ninguno de sus vendedores) antes del año 1995. 4. Obtener el número y nombre de las piezas que nunca hemos solicitado. 5. Obtener el número de los vendedores (numvend) que nos hubiesen podido servir todo lo que se solicita en las líneas 1, 2 y 3 del pedido número 1. 6. Obtener para los vendedores de Alicante o Madrid, el número y nombre de vendedor junto con el importe total que les hemos pagado a través de todos los pedidos que se les ha solicitado. 89 90 adicionales 5 EJERCICIOS ADICIONALES CONSULTAS 1. Obtener para los pedidos con un importe total entre 400 y 600 euros, el número de pedido, el número y nombre del vendedor al que se le solicitó, y la fecha del pedido. 2. Obtener para las piezas cuyo precio de suministro oscila entre 10 y 15, el número de la pieza, su nombre, y la cantidad de vendedores que nos la pueden suministrar a ese precio. 3. Obtener para los vendedores a los que les hayamos pagado en total (entre todos sus pedidos) más de 3000 euros, el número y nombre de vendedor junto con el importe total que les hemos pagado, y el total de pedidos que les hemos hecho. 4. Obtener para el número y nombre de los vendedores de Alicante a los que se les haya solicitado alguna pieza, de la que nos habían indicado que su plazo de suministro sería superior a una semana, junto con el número y nombre de la pieza, y la cantidad de pedidos distintos en los que se les ha solicitado. Ordena el resultado por la última columna. 5. Obtener el nombre de la empresa que tiene más de tres vendedores, y al menos dos de ellos son de la provincia de Alicante. 6. Obtener los nombre y empresas de los vendedores que no son de la Comunidad Valenciana, de los que se desconoce el teléfono. 91 92 adicionales 6 EJERCICIOS CONSULTAS 1. Obtener el nombre de la pieza (o piezas) y su precio unitario máximo de la pieza de precio unitario medio más bajo. 2. Nombre del vendedor y media de todos sus precios de suministro para los vendedores que viven en la misma ciudad que algún vendedor de apellido García. 3. Para la pieza (o piezas) de precio de venta mayor, obtener el nombre de la pieza y número total de vendedores que la pueden suministrar. 4. Obtener el nombre de vendedor para los vendedores cuya media de precio unitario de suministro sea máxima. 5. Obtener el nombre de la pieza y su precio unitario medio de la pieza más barata de precio de venta. 6. Nombre y empresa de los vendedores de la ciudad a la que se le ha solicitado más piezas. 7. Número de pedido, y número y nombre de vendedor del pedido que no es el de menor importe de venta (preciocompra*cantrecibida) siendo el año del pedido posterior al 1992 (>1992). 8. Nombre de los vendedores a los que se les haya solicitado más de dos pedidos en los que se sirvan discos duros. 9. Número de pieza, descripción y precio de venta de la pieza que más veces se ha pedido. 10. Número de pieza, descripción, precio medio de suministro y descuento máximo de las piezas que proceden de la misma ciudad que la empresa Mecemsa y que se han solicitado 2 veces o más. 93 94 adicionales 7 EJERCICIOS CONSULTAS 1. Número y nombre de los vendedores que oferten alguna de las piezas que pueden ser suministradas por el vendedor número 1, pero que no oferten ninguna de las que puedan ser suministradas por el vendedor número 2. 2. Obtener el número y el nombre de los vendedores y la cantidad de piezas que pueden suministrar a un precio entre 15 y 20 euros, ordenado por el nombre de vendedor. 3. Obtener, para el vendedor que cumple que la diferencia de precio al que le compramos una pieza y el precio que nos había ofrecido por ella sea máxima, el número de vendedor, su nombre y la diferencia media entre el precio al que nos vende las piezas y el que nos había ofrecido por las mismas. 4. Obtener el número de pieza de los teclados que nos han sido servidos en el mayo de cualquier año. 5. Obtener un listado en el que figure el número y nombre de la pieza , junto con el número y nombre de vendedor que nos ha ofertado la pieza, pero al que nunca se la hemos solicitado. 6. Obtener los números y nombres de los vendedores que nos han servido más de tres artículos diferentes. 95 96 SOLUCIONES SELECT1 Muchas de las soluciones también se muestran en álgebra relacional (AR) y cálculo relacional de tuplas (CRT), que son temas que se tratarán más adelante en las clases de teoría. En AR y CRT los resultados son relaciones, por lo tanto todas las soluciones que se muestran aquí corresponden al enunciado al que se esté dando respuesta, pero eliminando duplicados. En CRT se consideran declaradas correctamente todas las variables utilizadas. --1 select numpieza from pieza En AR PIEZA[numpieza] En CRT {P.numpieza/PIEZA(P)} --2 select nompieza from pieza where preciovent < 1000 En AR PIEZA donde preciovent<1000[nompieza] En CRT {P.nompieza / PIEZA(P) ∧ P.preciovent<1000} --3 select numpieza, nompieza, preciovent from pieza where preciovent > 10 or preciovent < 1 order by preciovent (la ordenación no se puede expresar ni En CRT ni En AR) En AR PIEZA donde preciovent>10 o preciovent<1 [numpieza,nompieza,preciovent] En CRT { P.nompieza, P.nompieza, P.preciovent / PIEZA(P) ∧ P.preciovent>1000 ∧ P.preciovent<10000} --4 select numpieza, descuento from preciosum order by descuento desc En AR PRECIOSUM [numpieza, descuento] En CRT {P.numpieza, P.descuento / PRECIOSUM(P)} --5 select nomvend from vendedor where numvend < 6 --6 select distinct nomvend from vendedor where numvend < 6 En AR VENDEDOR donde numvend<6 [nomvend] En CRT {V.nomvend / VENDEDOR(V) ∧ V.numvend<6} --7 select numvend, nomvend from vendedor where numvend < 6 En AR VENDEDOR donde numvend<6 [numvend, nomvend] En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ V.numvend<6} --8 select distinct numvend from preciosum --9 select numvend, nomvend from vendedor where provincia = 'ALICANTE' --10 select nomvend, nombrecomer from vendedor where provincia = 'ALICANTE' or provincia = 'CASTELLON' or provincia = 'VALENCIA' 97 --11 select numvend, diassum from preciosum where numpieza = 'P-0001-33' SOLUCIONES SELECT2 --2 select distinct numpieza, provincia from preciosum ps, vendedor v where ps.numvend = v.numvend order by numpieza desc (En AR y C.R.T. no se puede hacer order by) En AR Vendedor ∞ Preciosum [numpieza, provincia] En CRT {PS.numpieza, V.provincia/ Preciosum(PS) ∧ ∃ V(Vendedor(V) ∧ PS.numvend=V.numvend) } --9 select preciounit from preciosum where numvend = 100 and numpieza='A-1001-L' En AR Preciosum donde numvend=100 y numpieza=A-1001-L [precionuit] En CRT {PS.preciounit / Preciosum(PS) ∧ numvend=100 ∧ numpieza=A-1001-L } --17 select p.numpieza, nompieza from preciosum ps, pieza p where ps.numpieza=p.numpieza and (numvend = 2 or numvend = 4) En AR Pieza ∞ Preciosum donde numvend=2 o numvend=4 [numpieza, nompieza] En CRT {P.numpieza, P.nompieza/ Pieza(P) ∧ ∃ PR (Preciosum(PR) ∧ P.numpieza=PR.numpieza ∧ (numvend=2 ∨ numvend=4)) } --19 select nompieza, l.numpieza, preciovent from pieza pz, pedido p,linped l where numvend = 1 and p.numpedido=l.numpedido and l.numpieza=pz.numpieza En AR Pieza ∞ Linped ∞ Pedido donde numvend=1 [numpieza, nompieza, preciovent] En CRT {P.numpieza, P.nompieza P.preciovent/ Pieza(P) ∧ ∃ LP (Linped(LP) ∧ P.numpieza=LP.numpieza ∧ ∃ P (Pedido(P) ∧ LP.numpedido=P.numpedido ∧ numvend=1)) } SOLUCIONES SELECT3 En AR y CRT no existe el operador LIKE, ni el operador IS NULL, así como tampoco se puede establecer un criterio para ordenar el resultado. --1 select nompieza from pieza p, preciosum ps, vendedor v where p.numpieza = ps.numpieza and ps.numvend = v.numvend and nomvend like 'S%' 98 --2 select nompieza from pieza p, preciosum ps, vendedor v where p.numpieza = ps.numpieza and ps.numvend = v.numvend and (nomvend like 'S% MARTIN %' or nomvend like 'S% MARTINEZ %') --3 select nomvend from vendedor where provincia in ('ALICANTE', 'VALENCIA', 'CASTELLON') order by nomvend En AR Vendedor donde provincia=Alicante o provincia=Castellón o provincia=Valencia [nomvend] En CRT {V.nomvend / Vendedor(V) ∧ (provincia=Alicante ∨ provincia=Castellon ∨ provincia=Valencia)} --7 select nomvend from vendedor where nomvend like 'M_R%' order by nomvend --12 select * from vendedor where telefono is not null order by nomvend SOLUCIONES SELECT FECHA --1 select numpieza from inventario where fecharecuento=’15/10/1992’ --2 select numpieza from inventario where fecharecuento >= '1/10/1992' and fecharecuento <='31/10/1992' --3 select numpedido, fecha from pedido where fecha >= '1/7/1992' and fecha <= '31/12/1992'; select numpedido, fecha from pedido where to_char(fecha,'YY') = '92' and to_char(fecha,'MM') >= 6; --4 select distinct nomvend from vendedor v, pedido pd, linped l where v.numvend = pd.numvend and pd.numpedido = l.numpedido and to_char(fecharecep,'YYYY') = 1992 and to_char(fecharecep,'MM') = 5 and to_char(fecharecep,'DD') <= 15 order by nomvend --7 select distinct pz.numpieza, nompieza from linped l, pieza pz where l.numpieza = pz.numpieza and to_char(fecharecep,'DD') = 10 99 SOLUCIONES CREATE Algunas de las órdenes provocan errores, se debe identificar el origen del mismo. --1 tabla creada --2 ninguna fila seleccionada --3 1 fila creada --4 ERROR --5 1 fila creada --6 col1 col2 ---- ---1 AA 2 BB --9 tabla borrada --10 ERROR --11 tabla creada --12 1 fila 1 fila 1 fila 1 fila ERROR ERROR ERROR 1 fila 1 fila creada creada creada creada creada creada --13 create table listin (apodo varchar2(10), nombre varchar2(25), telefono varchar2(9), primary key (apodo) ); --14 drop table listin; create table listin (apodo varchar2(10), nombre varchar2(25), telefono varchar2(9), grado integer, primary key (apodo) ); --15 create table compra (orden integer, articulo varchar2(40), cantidad integer, formato varchar2(10), precioEstimado number(5,2), primary key (orden) ); SOLUCIONES MANIPULACIÓN1 --1 create table listin (apodo varchar2(10), nombre varchar2(25), telefono varchar2(9), grado integer, primary key (apodo) ); insert into listin (apodo,nombre,grado) values ('semao','Paco Musoso',2); insert into listin (apodo,nombre,grado,telefono) values ('aguila','Luis Ligero',1,'555111222'); 100 insert into listin (apodo,nombre,grado,telefono) values ('largo','Juan Pitillo',1,'555111333'); insert into listin (apodo,nombre,grado)values ('sobrao','Cristobal Garcilaso',5); --2 create table amistad (grado integer, descripcion varchar2(20), primary key (grado) ); --3 drop table listin; create table listin (apodo varchar2(10), nombre varchar2(25), telefono varchar2(9), grado integer, primary key (apodo), foreign key (grado) references amistad(grado) ); --4 ERROR: No se puede insertar ninguna fila restricción de integridad (BD1.SYS_C004090) violada - clave principal no encontrada SOLUCIONES MANIPULACIÓN2 -- 1 update inventario set fecharecuento=’01/01/2003’; -- 2 update inventario set cantminima=cantdisponible where cantdisponible<cantminima; -- 3 update vendedor set telefono='SIN TLFNO' where telefono is null; -- 4 update vendedor set calle='CENTRAL, 5', provincia='SALAMANCA', ciudad='SALAMANCA' where provincia='TOLEDO'; -- 5 update pieza set nompieza='SIN DESCRIPCION' where nompieza is null; -- 9 update pedido set numvend=1000 where numvend=200; --restricción de integridad violada -- 10 update pedido set numpedido=4 where numpedido=8; update pedido set numpedido=1 where numpedido=5; --restricción única violada update pedido set numpedido=8 where numpedido=2; --restricción de integridad violada, encontrado registro secundario update pedido set numpedido=3 where numpedido=2; --restricción única violada -- 13 update pieza set nompieza=(select nompieza from pieza where preciovent=7) where nompieza=’SIN DESCRIPCION’; --La subconsulta devuelve más de una fila 101 -- 16 update preciosum set (numpieza, preciounit) = (select numpieza, preciovent from pieza where nompieza = ‘DISKETTE 1.44 PANASONIC’) where numvend=200; --se viola la clave primaria de preciosum, ya que hay varias filas para --ese número de vendedor -- 17 update pedido set fecha=to_date(sysdate,’DDMMYYYY’) where numvend=3; -- 19 update inventario set periodorecuen = (select periodorecuen from inventario where fecharecuento > ‘1/01/2003’) where fecharecuento < ‘01/01/2003’; --la subconsulta puede devolver más de una fila SOLUCIONES MANIPULACIÓN3 -- 1 delete from vendedor where numvend = 1; -- 2 El vendedor 1 tiene suministros (PRECIOSUM) y pedidos (PEDIDO). Dada la definición de claves ajenas en PRECIOSUM, el borrar la fila de este vendedor provoca el borrado automático de todas sus filas en PRECIOSUM. También ocurre lo mismo en PEDIDOS, pero esta tabla está, a su vez, referenciada en LINPED con una clave ajena que también tiene establecida la PROPAGACIÓN como mecanismo para mantener la integridad referencial ante borrados en PEDIDO: todas las filas de los pedidos del vendedor 1 (los pedidos 1, 2, y 5) son eliminadas también. Resumiendo, por la definición de claves ajenas en la BD, el borrado del vendedor 1 afecta a las tablas PRECIOSUM, PEDIDO y LINPED, quedando PIEZA e INVENTARIO como estaban ya que en ellas no se generan problemas de integridad referencial. -- 3 delete from vendedor where numvend = 3; -- 4 El vendedor 3 tiene suministros (PRECIOSUM) y pero no pedidos. Borrar la fila de este vendedor provoca el borrado automático de todas sus filas en PRECIOSUM, pero no se producen más operaciones en ninguna otra tabla. -- 5 delete from vendedor where numvend = 8001; -- 6 El vendedor 8001 no tiene suministros (PRECIOSUM) ni pedidos. Por tanto, la única fila eliminada es la propia del vendedor en la tabla VENDEDOR. -- 7 delete from pedido where numpedido = 3; -- 8 El borrado del pedido 3 provoca la eliminación automática de todas sus líneas pedido pero nótese que el vendedor 2 (al que pertenecía este pedido) sigue estando en tabla VENDEDOR (como ocurría en las operaciones anteriores, por cierto, con las líneas pedido borradas automáticamente pero no sus piezas en PIEZA). Los únicos problemas integridad referencial, en este caso, se producen en LINPED. de la de de -- 9 delete from pieza where numpieza = ‘O-0001-PP’; La pieza ‘O-0001-PP’ tiene referencias en la tabla PRECIOSUM (también en LINPED), y como no se ha modificado la clave ajena en esta tabla, el sistema tiene como política asignada por defecto RECHAZAR: la operación ha generado un error. -- 10 delete from preciosum where numpieza = ‘O-0001-PP’; 102 -- 12 delete from pieza where numpieza = ‘O-0001-PP’; La pieza ‘O-0001-PP’ ya no tiene referencias en la tabla PRECIOSUM, pero sigue manteniendo las de LINPED. En esta tabla se ha definido la ANULACIÓN como política ante borrados en PIEZA: todas las referencias a esta pieza se han sustituido por NULOS. -- 14 delete from pieza where numpieza = ‘DD-0001-210’; La pieza ‘DD-0001-210’ no tiene referencias en la tabla PRECIOSUM puesto que las hemos eliminado en la orden 13, pero sí las tiene en LINPED e INVENTARIO. En ambas tablas se ha elegido la ANULACIÓN para las clavea ajenas a PIEZA, pero mientras es posible aplicarla en LINPED, en INVENTARIO es imposible ya que la clave ajena no admite nulos (es clave alternativa al definirla como UNIQUE y NOT NULL simultáneamente). La operación no puede realizarse. SOLUCIONES CONJUNTOS --1 select nombrecomer from vendedor v,pedido p where v.numvend=p.numvend UNION select nombrecomer from vendedor v, preciosum ps where v.numvend=ps.numvend and numpieza='A-1001-L' En AR Vendedor ∞ Pedido [nombrecomer] ∪ (Vendedor ∞ Preciosum donde numpieza = ‘A-1001-L’ [nombrecomer]) --2 select nombrecomer from vendedor v,pedido p where v.numvend=p.numvend INTERSECT select nombrecomer from vendedor v, preciosum ps where v.numvend=ps.numvend and numpieza='A-1001-L' --o también: select nombrecomer from vendedor v,pedido p, preciosum ps where v.numvend=p.numvend and v.numvend=ps.numvend and numpieza='A-1001-L' En AR Vendedor ∞ Pedido [nombrecomer] ∩ (Vendedor ∞ Preciosum donde numpieza = ‘A-1001-L’ [nombrecomer]) --3 En AR Vendedor ∞ Pedido [nombrecomer] - (Vendedor ∞ Preciosum donde numpieza = ‘A-1001-L’ [nombrecomer]) SOLUCIONES FUNCIONES --1 select numlinea, cantrecibida-cantpedida diferencia from linped where numpedido = 1 --2 select avg(abs(fecha-fecharecep)) mediarecep from linped l, pedido pd where pd.numpedido = 1 and l.numpedido = pd.numpedido --3 select count(distinct provincia) provincias from vendedor 103 --4 select min(preciocompra-preciounit) minimo from preciosum ps, pedido pd, linped l where ps.numvend = pd.numvend and pd.numpedido = l.numpedido and l.numpieza = ps.numpieza --5 select avg(distinct preciovent) mediaventa from pieza SOLUCIONES GROUP BY En AR y C.R.T. no hay definidas funciones agregadas por lo que muchos de los requerimientos nos los podríamos abordar, sobre todo si estas funciones agregadas aparecen en la cláusula SELECT. --1 select nompieza, preciovent, avg(preciovent-preciounit) media from pieza p, preciosum ps where p.numpieza=ps.numpieza group by p.numpieza,nompieza,preciovent order by nompieza --2 select numpedido, sum(preciocompra*cantrecibida) precioPagado, sum(cantpedida) cantidadPedida, sum(cantpedida-cantrecibida) no_recibido from linped group by numpedido order by numpedido --3 select count(*) vendedores, nombrecomer from vendedor group by nombrecomer order by vendedores desc, nombrecomer --4 select numpieza, max(cantpedida-cantrecibida) maximo from linped group by numpieza order by numpieza --5 select numpieza, count(*) vendedores from preciosum group by numpieza order by numpieza --6 select ps.numpieza, count(*) vendedores from preciosum ps, pieza p where ps.numpieza = p.numpieza and preciovent >= 250 group by ps.numpieza order by 2 --7 select numpieza,avg(preciounit) precio_Sum_Medio from preciosum group by numpieza order by numpieza --13 select p.numpieza, max(preciovent)/avg(preciocompra)*100 from linped l, pieza p where l.numpieza=p.numpieza group by p.numpieza order by p.numpieza 104 SOLUCIONES GROUP BY - HAVING En AR y CRT no hay definidas funciones de agregados por lo que muchos de los requerimientos nos los podríamos abordar, sobre todo si estas funciones agregadas aparecen en la cláusula SELECT. --1 select nombrecomer from vendedor group by nombrecomer having count(*)>2 En AR Define alias V1, V2 para VENDEDOR V1 × V2 × VENDEDOR donde V1.nombrecomer=V2.nombrecomer and V2.nombrecomer=Vendedor.nombrecomer and V1.numvend<>V2.numvend and V1.numvend<> VENDEDOR.numvend and V2.numvend<>Vendedor.numvend [V1.nombrecomer] En CRT {V1.nombrecomer | VENDEDOR(V1) ∧ ∃ V2(VENDEDOR(V2) ∧ V1.nombrecomer=V2.nombrecomer ∧ V1.numvend<>V2.numvend ∧ ∃ V3(VENDEDOR(V3) ∧ V2.nombrecomer=V3.nombrecomer ∧ V1.numvend<>V3.numvend ∧ V2.numvend<>V3.numvend))} --2 select numpedido from linped group by numpedido having count(*)>3 En AR Define alias LP1, LP2, LP3 para LINPED LP1 × LP2 × LP3 × LINPED donde LP1.numpedido=LP2.numpedido and LP2.numpedido=LP3.numpedido and LP3.numpedido=LINPED.numpedido and LP1.numlinea<>LP2.numlinea and LP1.numlinea<> LP3.numlinea and LP1.numlinea<> LINPED.numlinea and LP2.numlinea<> LP3.numlinea and LP2.numlinea<>LINPED.numlinea and LP3.numlinea<> LINPED.numlinea [LP1.numpedido] En CRT {LP1.numpedido | LINPED(LP1) ∧ ∃ LP2 ∃ LP3 ∃ LP4 (LINPED(LP2) ∧ LINPED(LP3) ∧ LINPED(LP4) ∧ LP1.numpedido=LP2.numpedido ∧ LP1.numlinea<>LP2.numlinea ∧ LP1.numlinea<>LP3.numlinea ∧ LP1.numlinea<>LP4.numlinea ∧ LP2.numpedido=LP3.numpedido ∧ LP3.numpedido=LP4.numpedido ∧ LP2.numlinea<>LP4.numlinea ∧ LP3.numlinea<>LP4.numlinea) } --3 select numpedido from linped group by numpedido having sum(cantpedida)>40 --4 select numpedido from linped l group by numpedido having sum(cantrecibida*preciocompra)>1000 --5 select numpieza, max(preciounit), count(*) from preciosum group by numpieza having avg(preciounit)>260 --6 select numpieza, max(preciounit) maximo, count(*) cuantos from preciosum where preciounit >= 250 group by numpieza having avg(preciounit)>260 --7 select p.numpedido, fecha from pedido p, linped l where p.numpedido=l.numpedido group by p.numpedido,fecha having sum(cantpedida)>30 and sum(cantrecibida)<10 105 --10 select p.numpieza,nompieza,max(preciounit) maximo from pieza p,preciosum ps where ps.numpieza=p.numpieza and preciovent > 250 or preciovent < 170 group by p.numpieza,nompieza having avg(descuento) between 10 and 17 and avg(preciounit) > 150 order by maximo SOLUCIONES SUBSELECT --1 select * from vendedor where numvend in (select numvend from pedido group by numvend having count(*) >= all(select count(*) from pedido group by numvend)) --2 select numvend, nomvend from vendedor where numvend not in (select numvend from preciosum) order by nomvend En AR (VENDEDOR[numvend] ∼ PRECIOSUM[numvend]) ∞ VENDEDOR[numvend, nomvend] En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ⎤ ∃ PR(PRECIOSUM(PR) ∧ PR.numvend=V.numvend)} --3a select v.numvend, nomvend from vendedor v, pedido p where v.numvend = p.numvend order by nomvend En AR VENDEDOR ∞ PEDIDO [numvend, nomvend] En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ P(PEDIDO(P) ∧ P.numvend=V.numvend)} --3b select numvend, nomvend from vendedor where numvend in (select numvend from pedido) order by nomvend --11 select v.numvend,count(distinct numpieza) npiezas from vendedor v, pedido p, linped l where v.numvend=p.numvend and p.numpedido=l.numpedido and nombrecomer in (select nombrecomer from vendedor group by nombrecomer having count(*) >= all (select count(*) from vendedor group by nombrecomer)) group by v.numvend order by v.numvend --15 select p.numpieza, nompieza,avg(preciounit),max(preciocompra) from pieza p, preciosum ps, linped l where p.numpieza=ps.numpieza and ps.numpieza=l.numpieza group by p.numpieza, nompieza having avg(preciounit)>= (select max(preciocompra) from linped where linped.numpieza=p.numpieza) 106 SOLUCIONES SUBSELECT - EXISTS --1 select nomvend from vendedor v where not exists (select * from pieza pz where not exists (select * from preciosum where numvend = v.numvend and numpieza = pz.numpieza)) En AR ((PRECIOSUM [numvend, numpieza] ÷ PIEZA[numpieza]) ∞ VENDEDOR) [nomvend] En CRT { V.nomvend / VENDEDOR(V) ∧ ∀P (PIEZA(P) ⇒ ∃ PR (PRECIOSUM(PR) ∧ PR.numvend=V.numvend ∧ PR.numpieza=P.numpieza ))} --2 select nomvend from vendedor where numvend not in (select numvend from preciosum) order by nomvend --2 select nomvend from vendedor v where not exists (select * from preciosum where numvend = v.numvend) order by nomvend En AR ((VENDEDOR[numvend] ∼ PRECIOSUM[numvend]) ∞ VENDEDOR)[nomvend] En CRT {V.nomvend / VENDEDOR(V) ∧ ⎤ ∃ PR(PRECIOSUM(PR) ∧ PR.numvend=V.numvend)} --3 select numpieza, nompieza from pieza pz where not exists (select * from pedido pd where numvend=1 and not exists (select * from linped l where pd.numpedido=l.numpedido and pz.numpieza=l.numpieza)) En AR ((LINPED [numpieza, numpedido] ÷ (PEDIDO donde numvend=1)[numpedido]) ∞ PIEZA) [numpieza, nompieza] En CRT { P.numpieza, P.nompieza / PIEZA(P) ∧ ∀PD (PEDIDO(PD) ∧ PD.numvend=1 ⇒ ∃ LP (LINPED(LP) ∧ LP.numpedido=PD.numpedido ∧ LP.numpieza=P.numpieza ))} --4 select distinct nombrecomer from vendedor v where not exists (select * from vendedor where nombrecomer = v.nombrecomer and provincia not in ('ALICANTE','CASTELLON','VALENCIA')) order by nombrecomer En AR VENDEDOR[nombrecomer] ∼ (VENDEDOR donde provincia<>ALICANTE or provincia<>CASTELLON or provincia<>VALENCIA)[nombrecomer] En CRT { V.nombrecomer / VENDEDOR(V) ∧ ∀ V2 (VENDEDOR(V2) ∧ V2.nombrecomer=V.nombrecomer ⇒ (V2.provincia=ALICANTE ∨ V2.provincia=CASTELLON ∨ V2.provincia=VALENCIA))} O bien { V.nombrecomer / VENDEDOR(V) ∧ ⎤ ∃ V2 (VENDEDOR(V2) ∧ V2.nombrecomer=V.nombrecomer ∧ V2.provincia<>ALICANTE ∧ V2.provincia<>CASTELLON ∧ V2.provincia<>VALENCIA))} 107 SOLUCIONES ADICIONALES 1 --3 select distinct numvend from preciosum ps, pieza p, linped l where ps.numpieza = p.numpieza and p.numpieza = l.numpieza and preciovent between 50 and 100 order by numvend En AR PIEZA ∞ PRECIOSUM ∞ LINPED donde preciovent≥50 and preciovent≤100 [numvend] En CRT {PR.numvend / PRECIOSUM(PR) ∧ ∃ P (PIEZA(P) ∧ P.numpieza=PR.numpieza ∧ preciovent≥5000 ∧ preciovent≤10000 ∧ ∃ LP (LINPED(LP) ∧ PR.numpieza=LP.numpieza)) } --4 select nombrecomer from vendedor v, pedido pd, linped l, pieza p where v.numvend = pd.numvend and pd.numpedido = l.numpedido and l.numpieza = p.numpieza and nompieza like '%MONITOR%' and provincia = 'ALICANTE' --5 select nompieza, p.numpieza from pieza p, linped l where p.numpieza = l.numpieza order by nompieza En AR PIEZA ∞ LINPED [numpieza, nompieza] En CRT {P.numpieza, P.nompieza / PIEZA(P) ∧ ∃ LP (LINPED(LP) ∧ P.numpieza=LP.numpieza) } --6 select ps.numpieza, preciounit - preciocompra from linped l, pedido pd, preciosum ps where l.numpedido = pd.numpedido and pd.numvend = ps.numvend and ps.numpieza = l.numpieza order by diferencia En AR PRECIOSUM ∞ PEDIDO ∞ LINPED [numpieza, preciounit, preciocompra] En CRT {PR.numpieza, PR.preciounit, LP.preciocompra / PRECIOSUM(PR) ∧ LINPED(LP) ∧ ∃ P (PEDIDO(P) ∧ PR.numvend=P.numvend ∧ P.numpedido=LP.numpedido ∧ PR.numpieza=LP.numpieza) } En AR y C.R.T.: no está considerada, en la formalización de estos lenguajes, la resta como resultado. --7 select distinct v.numvend, nombrecomer from vendedor v, pedido pd, linped l, preciosum ps where ps.numvend = v.numvend and v.numvend = pd.numvend and pd.numpedido = l.numpedido and l.numpieza = ps.numpieza and preciocompra > preciounit En AR VENDEDOR ∞ PRECIOSUM ∞ PEDIDO ∞ LINPED donde preciocompra > preciounit [numvend, nomvend] En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ PR(PRECIOSUM(PR) ∧ V.numvend=PR.numvend ∧ ∃ P (PEDIDO(P) ∧ PR.numvend=P.numvend ∧ ∃ LP(LINPED(LP) ∧ P.numpedido=LP.numpedido ∧ PR.numpieza=LP.numpieza ∧ preciocompra > p 109 SOLUCIONES ADICIONALES 2 --1 select nomvend,count(*) cantidad from preciosum ps, vendedor v where ps.numvend=v.numvend group by v.numvend,nomvend order by nomvend --2 select v.numvend,nomvend,count(*) cantidad from preciosum ps, vendedor v where ps.numvend=v.numvend group by v.numvend,nomvend order by nomvend --6 select numvend, nomvend from vendedor v, pedido p, linped lp where v.numvend = p.numvend and p.numpedido = lp.numpedido group by p.numpedido,v.numvend, nomvend having count(distinct numpieza)> 3 En AR Define alias LP1, LP2, LP3 para LINPED LP1 × LP2 × LP3 × LINPED donde LP1.numpedido=LP2.numpedido and LP2.numpedido=LP3.numpedido and LP3.numpedido=LINPED.numpedido and LP1.numpieza<>LP2.numpieza and LP1.numpieza<> LP3.numpieza and LP1.numpieza<> LINPED.numpieza and LP2.numpieza<> LP3.numpieza and LP2.numpieza<>LINPED.numpieza and LP3.numpieza<> LINPED.numpieza [LP1.numpedido] ∞ PEDIDO ∞ VENDEDOR [numvend, nomvend] En CRT {V.numvend, V.nomvend / VENDEDOR(V) ∧ ∃ P (PEDIDO(P) ∧ P.numvend=V.numvend) ∧ ∃ LP1 ( LINPED(LP1) ∧ LP1.numpedido=P.numpedido ∧ ∃ LP2 (LINPED(LP2) ∧ LP1.numpedido=LP2.numpedido ∧ ∧ LP1.numpieza<>LP2.numpieza ∧ ∃ LP3 (LINPED(LP3) ∧ LP2.numpedido=LP3.numpedido ∧ LP1.numpieza<>LP3.numpieza ∧ LP2.numpieza<>LP3.numpieza ∧ ∃ LP4 (LINPED(LP4) ∧ LP3.numpedido=LP4.numpedido ∧ LP1.numpieza<>LP4.numpieza ∧ LP2.numpieza<>LP4.numpieza ∧ LP3.numpieza<>LP4.numpieza))))) } --4 select p.numpedido, count(*), p.numvend, nomvend, fecha from pedido p, linped l, vendedor v where p.numvend = v.numvend and p.numpedido = l.numpedido group by p.numpedido, p.numvend, nomvend, fecha (en este caso coincide count(*) y count(distinct numlinea) --7 select v.numvend, nomvend from vendedor v, pedido p where v.numvend = p.numvend --8 select nompieza, avg(preciosum), preciovent from preciosum ps, pieza p where p.numpieza = ps.numpieza group by nompieza, preciovent having avg(preciosum) > 100 and count(*) > 2 (aquí también coincide count(*) y count(distinct numvend) --9 select nompieza, avg(preciounit) media, preciovent from preciosum ps, pieza p where ps.numpieza=p.numpieza and preciovent > 30000 group by p.numpieza,nompieza,preciovent having count(*)>2 and avg(preciounit) between 100 and 280 order by p.nompieza --10 select p.numpieza, nompieza from pieza p, preciosum ps where p.numpieza = ps.numpieza group by p.numpieza, nompieza, preciovent having preciovent*20/100 > avg(preciounit) (necesito poner el preciovent en el group by porque es no calculado) 110 SOLUCIONES ADICIONALES 3 --1 select v.numvend, nomvend, count(*) cantidadPED from vendedor v, pedido p where v.numvend=p.numvend and provincia=’ALICANTE’ group by v.numvend, nomvend --4 select p.numpieza, nompieza, max(preciounit) maxPrecio, min(preciounit) minPrecio, count(*) totalVend from preciosum ps, pieza p where ps.numpieza=p.numpieza group by p.numpieza, nompieza having avg(preciounit)<10 --5 select p.numpedido, v.numvend, nomvend, count(distinct fecharecep) from vendedor v, pedido p, linped lp where v.numvend = p.numvend and p.numpedido = lp.numpedido group by p.numpedido, v.numvend, nomvend having count(distinct fecharecep)> 1 --7 select p.numpieza, nompieza, v.numvend, nomvend from pieza p, linped lp , pedido ped, vendedor v where lp.numpieza=p.numpieza and lp.numpedido=ped.numpedido and ped.numvend=v.numvend and to_char(fecharecep, ‘d’)=7 order by 2 SOLUCIONES ADICIONALES 4 --1 select v.numvend, nomvend from pedido p, vendedor v where p.numvend=v.numvend and to_char(fecha,‘yyyy’)=1995 minus select v.numvend, nomvend from pedido p, vendedor v where p.numvend=v.numvend and to_char(fecha,‘yyyy’)=1992 --4 select numpieza, nompieza from pieza minus select p.numpieza, nompieza from linped lp, pieza p where lp.numpieza=p.numpieza En AR PIEZA[numpieza, nompieza] ∼ (PIEZA ∞ LINPED)[numpieza, nompieza] En CRT {P.numpieza, P.nompieza / PIEZA(P) ∧ ⎤ ∃ LP(LINPED(LP) ∧ LP.numpieza=P.numpieza} 111 --5 select numvend from preciosum ps, linped lp where ps.numpieza=lp.numpieza and numpedido=1 and numlinea=1 intersect select numvend from preciosum ps, linped lp where ps.numpieza=lp.numpieza and numpedido=1 and numlinea=2 intersect select numvend from preciosum ps, linped lp where ps.numpieza=lp.numpieza and numpedido=1 and numlinea=3 En AR Define alias V1, V2 para VENDEDOR PRECIOSUM [numvend, numpieza] ÷ LINPED DONDE (numpedido=1 and (numlinea=1 or numlinea=2 or numlinea=3)) [numpieza] En CRT {V.numvend / VENDEDOR(V) ∧ ∀ LP (LINPED(LP) ∧ LP.numpedido=1 ∧ (LP.numlinea=1 ∨ LP.numlinea=2 ∨ LP.numlinea=3) ⇒ ∃ PS(PRECIOSUM(PS) ∧ PS.numpieza=LP.numpieza ∧ PS.numvend=V.numvend) ) } --6 select v.numvend, nomvend, sum(cantrecibida*preciocompra) Total from vendedor v, pedido p, linped lp where v.numvend=p.numvend and p.numpedido=lp.numpedido and provincia I (‘ALICANTE’, ‘MADRID’) group by v.numvend, nomvend SOLUCIONES ADICIONALES 5 --1 select p.numpedido, v.numvend, nomvend, fecha from pedido p, linped lp, vendedor v where p.numvend=v.numvend and p.numpedido=lp.numpedido group by p.numpedido, fecha, v.numvend, nomvend having sum(ctdpedida*preciocompra) between 400 and 600 --4 select v.numvend, nomvend, p.numpieza, nompieza, count(distinct numpedido) from vendedor v, preciosum ps, pedido pd, linped lp, pieza p where v.numvend = pd.numvend and v.numvend=ps.numvend and pd.numpedido = lp.numpedido and p.numpieza=lp.numpieza and p.numpieza=ps.numpieza and diassum>7 group by v.numvend, nomvend, p.numpieza, nompieza order by 5 --5 select nombrecomer from vendedor group by nombrecomer having count(*)>3 intersect select nombrecomer from vendedor where provincia=’AICANTE’ group by nombrecomer having count(*)>1 --6 select nomvend, nombrecomer from vendedor where provincia not in (‘ALICANTE’,’CASTELLON’,’VALENCIA’) and telefono is null 112 SOLUCIONES ADICIONALES 6 --2 select nomvend, avg(preciounit) mediasumin from vendedor v, preciosum ps where v.numvend=ps.numvend and ciudad IN (select ciudad from vendedor where nomvend like '%GARCIA%') group by v.numvend, nomvend,ciudad order by mediasumin --7 select numpedido, v.numvend, nomvend, fecha from pedido p, vendedor v where p.numvend=v.numvend and to_char(fecha,'YYYY')>1992 and numpedido in (select numpedido from linped group by numpedido having sum(preciocompra*cantrecibida) > any (select sum(preciocompra*cantrecibida) from linped group by numpedido)) --10 select ps.numpieza, nompieza, avg(preciounit) media, max(descuento) descuento from preciosum ps, pieza pz, vendedor v where ps.numpieza=pz.numpieza and v.numvend=ps.numvend and v.ciudad in (select ciudad from vendedor where nombrecomer='MECEMSA') and ps.numpieza in (select numpieza from linped group by numpieza having count(*)>1) group by ps.numpieza,nompieza order by ps.numpieza SOLUCIONES ADICIONALES 7 --1 select v.numvend, nomvend from vendedor v, preciosum ps where v.numvend=ps.numvend and numpieza IN (select numpieza from preciosum where numvend=1) and numvend NOT IN ( select v.numvend, nomvend from vendedor v, preciosum ps where v.numvend=ps.numvend and numpieza IN (select numpieza from preciosum where numvend=2)) 113 --1 select numvend, nomvend from vendedor where numvend IN ( select numvend from preciosum where numpieza IN (select numpieza from preciosum where numvend=1) MINUS select numvend from preciosum where numpieza IN (select numpieza from preciosum where numvend=2)) En AR (PRECIOSUM donde numvend=1 [numpieza] ∞ PRECIOSUM ∞ VENDEDOR)[numvend, nomvend] ∼ (PRECIOSUM donde numvend=2 [numpieza] ∞ PRECIOSUM ∞ VENDEDOR)[numvend, nomvend] En CRT {V1.numvend, V1.nomvend / VENDEDOR(V1) ∧ ∃ PS1(PRECIOSUM(PS1) ∧ PS1.numvend=V1.numvend ∧ ∃ PS2(PRECIOSUM(PS2) ∧ PS2.numvend=1 ∧ PS1.numpieza=PS2.numpieza ∧ ⎤ ∃ PS3(PRECIOSUM(PS3) ∧ PS3.numvend=V1.numvend ∧ ∃ PS4(PRECIOSUM(PS4) ∧ PS4.numvend=2 ∧ PS3.numpieza=PS4.numpieza)) ) ) } --3 select v.numvend, nomvend, avg(preciocompra-preciounit) DifMedia from preciosum ps, pedido p, linped lp, vendedor v where p.numpedido=lp.numpedido and ps.numvend=p.numvend and lp.numpieza=ps.numpieza and p.numvend=v.numvend group by v.numvend, nomvend having max(precicompra-preciounit) = (Select max(preciocompra–preciounit) from preciosum ps, pedido p, linped lp where p.numpedido=lp.numpedido and ps.numvend=p.numvend and lp.numpieza=ps.numpieza) --4 select numpieza from pieza p, linped lp where p.numpieza=lp.numpieza and nompieza like ‘%TECLADO%’ and to_char(fecharecep, ‘mm’)=5 --6 select v.numvend, nomvend from vendedor v, pedido p, linped lp where v.numvend=p.numvend and p.numpedido=lp.numpedido group by v.numvend, nomvend having count(distinct numpieza)>3 114