Académique Documents
Professionnel Documents
Culture Documents
TEMA
8
CONSULTAS A MLTIPLES TABLAS
Introduccin
En este captulo aprenderemos a utilizar SQL para recuperar datos a partir de una o ms tablas.
77
Asignatura: Sistemas de Base de Datos 1. En la clusula SELECT, liste todas las columnas que quiera mostrar. 2. En la clusula FROM, liste todas las tablas implicadas en la consulta. 3. En la clusula WHERE, liste la condicin que restringe los datos a recuperar a slo las filas de las dos tablas que coincidan, es decir, restrnjala a las filas que tengan valores comunes en columnas coincidentes. Como vimos anteriormente, normalmente es necesario calificar un nombre de columna para especificar la columna en concreto a la que nos referimos. Calificar nombres de columna es especialmente importante al unir tablas, porque debemos unir las tablas en columnas coincidentes que suelen tener nombres de columna idnticos. Para calificar un nombre de columna, preceda el nombre de la columna con el nombre de la tabla, seguido en un punto. Las columnas coincidentes en este ejemplo son las que se llaman codiVende: Hay una columna en la tabla tVendedor llamada codiVende y una columna en la tabla tCliente que tambin se llama codiVende. La columna codiVende de la tabla tVendedor se escribe como tVendedor.codiVende y la columna codiVende de la tabla tCliente se escribe tCliente.codiVende. En la figura 5.1 vemos la consulta y sus resultados. Cuando existe una ambigedad potencial al listar nombres de columnas, es necesario calificar las columnas implicadas en la consulta. Tambin se pueden calificar otras columnas, incluso cuando no hay confusin posible. Algunos usuarios prefieren calificar todos los nombres de columnas, pero en este libro solo calificaremos nombres de columnas cuando sea necesario.
SELECT codiClien, nombreClien, tVendedor.codiVende, apeVende, nombreVende FROM tVendedor, tCliente WHERE tVendedor.codiVende = tCliente.codiVende;
Figura 5.1. Unir dos tablas con un solo comando SQL. Preguntas y Respuestas Pregunta: En la primera fila del resultado de la figura 5.1, el cdigo de cliente es 148, y el nombre de cliente es Als Appliance and Sport. Estos valores representan la primera fila de la tabla tCliente. Por qu el cdigo de vendedor es 20, el apellido del vendedor Kaiser y su nombre Valerie?
78
Respuesta: En la tabla tCliente el cdigo de vendedor para el cdigo de cliente 148 es 20. (Esto indica que el cdigo de cliente 148 est relacionada con el cdigo de vendedor 20) En la tabla tVendedor, el apellido del cdigo de Vendedor 20 es Kaiser y su nombre Valerie.
Ejemplo 02 Liste el cdigo y nombre de los clientes cuyo lmite de crdito sea 7500, junto con el cdigo, apellido y nombre del vendedor que representa al cliente. En el ejemplo 1 utilizamos una condicin en la clusula WHERE slo para relacionar un cliente con un vendedor para unir las tablas. Aunque relacionar un cliente con un vendedor es esencial en este ejemplo tambin, tenemos que restringir los resultados a solo aquellos clientes cuyo lmite de crdito sea 7500. Podemos restringir las filas utilizando una condicin compuesta, como vemos en la figura 5.2.
SELECT codiClien, nombreClien, tVendedor.codiVende, apeVende, nombreVende FROM tVendedor, tCliente WHERE tVendedor.codiVende = tCliente.codiVende AND limiCreClien = 7500;
Ejemplo 3 Para cada artculo pedido, liste el cdigo de pedido, el cdigo de artculo, la descripcin del artculo, el nmero de unidades pedidas, el precio cotizado y el precio unitario. Un artculo se considera pedido cuando hay una fila en la tabla tDetallePedido en la que aparece el artculo. Podemos encontrar el cdigo de pedido, el nmero de unidades pedidas y el precio cotizado en la tabla tDetallePedido. Sin embargo, para encontrar la descripcin del artculo y el precio unitario, tenemos que buscar en la tabla tArticulo. Despus tenemos que buscar filas en la tabla tDetallePedido y filas en la tabla tArticulo que coincidan (filas que contengan el mismo cdigo de artculo). En la figura 5.3 vemos la consulta y sus resultados.
SELECT codiPedi, tArticulo.codiArti, descripArti, cantiArti, precioCoArti, precioUArti FROM tDetallePedido, tArticulo WHERE tDetallePedido.codiArti = tArticulo.codiArti;
79
Figura 5.3. Unir las tablas tDetallePedido y tArticulo. Preguntas y Respuestas Pregunta: Se puede utilizar tArticulo.codiArti en lugar de tDetallePedido.codiArti en la clusula SELECT? Respuesta: S. Los valores de esas dos columnas coinciden porque han de cumplir la condicin tDetallePedido.codiArti = tArticulo.codiArti.
Operador IN
Otra manera de recuperar datos de mltiples tablas en una consulta es utilizando el operador IN con una subconsulta. En el ejemplo 4, primero, podramos utilizar una subconsulta para encontrar todos los cdigos de artculo en la tabla tDetallePedido que aparecen en todas las filas en las que
80
Asignatura: Sistemas de Base de Datos el cdigo de Pedido sea 21610. Despus podemos encontrar la descripcin del artculo de todos los artculos cuyo cdigo est en la lista. En la figura 5.5 vemos la consulta y sus resultados.
SELECT descripArti FROM tArticulo, tDetallePedido WHERE tArticulo.codiArti = tDetallePedido.codiArti AND codiPedi = '21610';
Figura 5.4. Restringir las filas al unir las tablas tDetallePedido y tArticulo.
SELECT descripArti FROM tArticulo WHERE codiArti IN (SELECT codiArti FROM tDetallePedido WHERE codiPedi = '21610');
Figura 5.5. Utilizar el operador IN en lugar de unir dos tablas para consultarlas. En la figura 5.5, al evaluar la subconsulta se produce una tabla temporal que consiste en los cdigos de artculo (DR93 y DW11) que estn presentes en el cdigo de pedido 21610. Al ejecutar el resto de la consulta se producen las descripciones del artculo para cada artculo cuyo cdigo est en la tabla temporal, en este caso, Gas Range (DR93) y Washer (DW11).
Operador EXISTS
Tambin podemos utilizar el operador EXISTS para recuperar datos desde ms de una tabla, como vemos en el ejemplo 5. El operador EXISTS comprueba la existencia de filas que cumplan algunos criterios. Ejemplo 5 Busque el cdigo de pedido y la fecha de todos los pedidos que contengan el cdigo de artculo DR93. Esta consulta es similar a la del ejemplo 4, pero esta vez implica a la tabla tPedido en lugar de la tabla tArticulo. En este caso, podemos escribir la consulta de cualquiera de las dos maneras que hemos visto. Por ejemplo, podramos utilizar el operador IN con una subconsulta, como vemos en la figura 5.6.
SELECT codiPedi, fechaPedi FROM tPedido WHERE codiPedi IN (SELECT codiPedi FROM tDetallePedido WHERE codiArti = 'DR93');
81
Figura 5.6. Operador IN para seleccionar informacin del pedido. Otro mtodo de resolver el ejemplo 5 es con el operador EXISTS, como vemos en la figura 5.7.
SELECT codiPedi, fechaPedi FROM tPedido WHERE EXISTS (SELECT * FROM tDetallePedido WHERE tPedido.codiPedi = tDetallePedido.codiPedi AND codiArti = 'DR93');
Figura 5.7. Operador EXISTS para seleccionar informacin del pedido. La subconsulta de la figura 5.7 es la primera que hemos visto que implica a una tabla listada en la consulta exterior. Este tipo de consulta se denomina subconsulta correlacionada. En este caso se utiliza en la subconsulta la tabla tPedido, que est listada en la clusula FROM de la consulta exterior. Por este motivo tenemos que calificar la columna codiPedi en la subconsulta (tPedido.codiPedi). En las consultas anteriores con el operador IN no era necesario calificar las columnas. La consulta que vemos en la figura 5.7 funciona de esta manera: para cada fila de la tabla tPedido, la subconsulta se ejecuta utilizando el valor de tPedido.codiPedi que ocurre en esa fila. La consulta interior produce una lista de todas las filas de la tabla tDetallePedido en las que tDetallePedido.codiPedi coincida con este valor y en las que codiArti sea igual a DR93. Podemos preceder una subconsulta del operador EXISTS para crear una condicin que ser verdadera si se obtienen una o ms filas cuando se ejecuta la subconsulta o de lo contrario la condicin ser falsa. Para comprender mejor el proceso, considere los cdigos de pedido 21610 y 21613 de la tabla tPedido. El cdigo de pedido 21610 se incluye porque existe una fila en la tabla tDetallePedido con este cdigo de pedido y el cdigo de artculo DR93. Cuando se ejecuta la subconsulta, habr al menos una fila en los resultados, que a su vez hacen que la condicin EXISTS sea verdadera. Sin embargo, el cdigo de pedido 21613 no se incluir, porque no existe ninguna fila en la tabla tDetallePedido con este cdigo de pedido y el cdigo de artculo DR93. No habr ninguna fila en los resultados de la subconsulta, lo que a su vez hace que la condicin EXISTS sea falsa.
82
Ejemplo 6 Busque el cdigo y la fecha de los pedidos que incluyan un artculo situado en el almacn 3. Una manera de solucionar este problema es primeramente determinado la lista de cdigos de artculo en la tabla tArticulo de los artculos situados en el almacn 3. Despus obtendremos una lista de cdigos de pedido de la tabla tDetallePedido con un cdigo de artculo correspondiente en la lista de cdigos de artculo. Por ltimo, recuperaremos esos nmeros y fechas de pedido de la tabla tPedido para los que el cdigo de pedido est en la lista de cdigos de pedido obtenidos durante el segundo paso. La consulta y sus resultados aparecen en la figura 5.8.
SELECT codiPedi, fechaPedi FROM tPedido WHERE codiPedi IN (SELECT codiPedi FROM tDetallePedido WHERE codiArti IN (SELECT codiArti FROM tArticulo WHERE almaArti = '3'));
Figura 5.8. Subconsultas anidadas (una subconsulta dentro de otra). Como se puede esperar, SQL evala las consultas desde la ms interior hasta la ms exterior. La consulta de este ejemplo se evala en tres pasos: 1. La subconsulta interior es la primera que se evala, produciendo una tabla temporal de cdigos de artculo para aquellos artculos situados en el almacn 3. 2. Despus se evala la siguiente subconsulta (intermedia), produciendo una segunda tabla temporal con una lista de cdigos de pedido. Cada cdigo de pedido de este conjunto tiene una fila en la tabla tDetallePedido para la que el cdigo de artculo est en la tabla temporal producida en el paso 1. 3. La consulta exterior se evala en ltimo lugar, produciendo la lista deseada de cdigos y fechas de pedido. Slo se incluyen en los resultados los pedidos cuyos cdigos estn en la tabla temporal producida en el paso 2. Otra manera de resolver el ejemplo 6 sera uniendo las tablas tPedido, tDetallePedido y tArticulo. En la figura 5.9 vemos la consulta y sus resultados.
SELECT tPedido.codiPedi, fechaPedi FROM tPedido, tDetallePedido, tArticulo WHERE tPedido.codiPedi = tDetallePedido.codiPedi AND tDetallePedido.codiArti = tArticulo.codiArti AND almaArti = '3';
83
Figura 5.9. Unir tres tablas. En esta consulta las tablas se unen con las siguientes condiciones: tDetallePedido.codiPedi = tPedido.codiPedi tDetallePedido.codiArti = tArticulo.codiArti La condicin almaArti = 3 restringe el resultado a solo aquellas partidas situadas en el almacn 3. Los resultados de las consultas son correctos, independientemente de qu comando utilicemos. Podemos utilizar el mtodo que prefiramos. Pero, hay alguno que sea ms eficaz que el otro? SQL lleva a cabo muchas optimizaciones predefinidas que analizan las consultas para determinar la mejor manera de satisfacerlas. Con un buen optimizador, en principio la manera de formular una consulta no debera ser muy relevante, en este caso las subconsultas anidadas pueden llevar algo ms de tiempo que la unin de tablas. Sin embargo, si utilizamos un DBMS sin optimizador, la manera de escribir una consulta puede suponer una diferencia importante en la velocidad a la que el DBMS ejecuta la consulta. Cuando trabajamos con una base de datos muy grande y la eficiencia es fundamental, es recomendable consultar el manual del DBMS o probar algunos tiempos. Intente ejecutar la misma consulta de las dos maneras para ver si observa diferencias en velocidad de ejecucin. En base de datos pequeas no debera haber una diferencia significativa de tiempo entre los dos mtodos.
Ejemplo prctico
En la consulta del ejemplo 7 intervienen varias de las funciones que ya hemos visto. Aparecen en ella las principales clusulas que se pueden utilizar en un comando SELECT. Tambin se ve el orden en que las clusulas han de aparecer. Ejemplo 7 Liste el cdigo de cliente, cdigo de pedido, fecha de pedido y total de todos los pedidos que excedan de 1000. Asigne el nombre de columna TotalPedido a la columna que muestre los totales del pedido. En la figura 5.10 vemos la consulta y sus resultados. En esta consulta, las tablas tPedido y tDetallePedido se unen al listarlas en la clusula FROM y relacionarlas en la clusula WHERE. Los datos seleccionados estn ordenados por cdigo de pedido utilizando la clusula ORDER BY. La clusula GROUP BY indica que los datos se deben agrupar por cdigo de pedido, cdigo de cliente y fecha de pedido. Para cada grupo, la clusula SELECT muestra el cdigo de cliente, el cdigo de pedido, la fecha de pedido y el total (SUM(cantiArti*PrecioCoArti)). Adems, el total se ha renombrado como TotalPedido. Sin embargo, no se mostrarn todos los grupos. La clusula HAVING muestra solo los grupos cuyo (SUM(cantiArti*PrecioCoArti)) es mayor que 1000.
84
Figura 5.10. Ejemplo prctico. El cdigo de pedido, nombre de cliente y fecha de pedido son nicos para cada pedido. Por tanto, podra parecer que simplemente agrupando por cdigo de pedido ser suficiente. SQL requiere que tanto el cdigo de cliente como la fecha de pedido estn listados en la clusula GROUP BY. Recuerde que una clusula SELECT puede incluir estadsticas calculadas para slo los grupos o columnas cuyos valores sean idnticos en cada fila de un grupo. Estableciendo que los datos se agrupen por cdigo de pedido, nombre de cliente y fecha de pedido, estamos indicando a SQL que los valores de esas columnas deben ser iguales en cada fila de un grupo.
Alias
Cuando se listan las tablas en la clusula FROM, podemos asignar a cada tabla un alias, o nombre alternativo, que podemos utilizar en el resto de la declaracin. Un alias se crea escribiendo el nombre de la tabla, pulsando la barra espaciadora y despus escribiendo el nombre del alias. No es necesario separar ambos nombres con comas ni puntos. Los alias se utilizan a efectos de simplificar. En el ejemplo 8 asignaremos a la tabla tVendedor el alias V y a la tabla tCliente el alias C. De esta manera, podemos escribir el resto de la consulta V en lugar de tVendedor y C en lugar de tCliente. La consulta de este ejemplo es muy sencilla y, por tanto, las ventajas no son obvias, pero cuando una consulta es completa y requiere que califiquemos los nombres, el uso de alias puede simplificar el proceso considerablemente. Ejemplo 8 Liste el cdigo, apellido y nombre de todos los vendedores junto con el cdigo y nombre de los clientes a los que representa. En la figura 5.11 vemos la consulta y su resultado utilizando alias.
SELECT V.codiVende, apeVende, nombreVende, codiClien, nombreClien FROM tVendedor V, tCliente C WHERE V.codiVende = C.codiVende;
85
Figura 5.11. Alias en una consulta. Nota: Tcnicamente, no es necesario calificar codiClien, porque solamente se incluye en la tabla tCliente. En la figura 5.11 la calificamos solamente para demostrar el efecto.
86
Figura 5.12. Utilizar alias para una auto-unin. Estamos solicitando un cdigo de cliente y un nombre a la tabla P, seguidos de un cdigo de cliente y un nombre a la tabla S, y despus la ciudad. (Puesto que la ciudad en la primera tabla debe coincidir con la ciudad de la segunda, podemos seleccionar la ciudad de cualquiera de las dos tablas.) La clusula WHERE contiene dos condiciones: las ciudades han de coincidir, el cdigo de cliente de la primera tabla debe ser menor que el cdigo de cliente de la segunda tabla. Adems, la clusula ORDER BY asegura que los datos queden ordenados por el primer cdigo de cliente. En las filas con el mismo primer cdigo de cliente, los datos se ordenan adems por el segundo cdigo de cliente.
87
Asignatura: Sistemas de Base de Datos La primera condicin relaciona un pedido a una lnea de pedido con un cdigo de pedido correspondiente. La segunda condicin relaciona el cliente con el pedido con el cdigo de cliente correspondiente. La condicin final relaciona el vendedor a un cliente con un cdigo de vendedor coincidente. Para la consulta completa, listaremos todas las columnas deseadas en la clusula SELECT y calificaremos las columnas que aparezcan en ms de una tabla. En la clusula FROM, listaremos las tablas implicadas en la consulta. En la figura 5.16 vemos la consulta y sus resultados.
SELECT codiArti, cantiArti, tPedido.codiPedi, fechaPedi, tCliente.codiClien, nombreClien, apeVende FROM tVendedor, tCliente, tPedido, tDetallePedido WHERE tVendedor.codiVende = tCliente.codiVende AND tCliente.codiClien = tPedido.codiClien AND tPedido.codiPedi = tDetallePedido.codiPedi;
Figura 5.16. Unir cuatro tablas en una consulta. Preguntas y respuestas Pregunta: Por qu la columna codiArti, que aparece en las tablas tArticulo y tDetallePedido, no est calificada en la clusula SELECT? Respuesta: Entre las tablas listadas en la consulta, slo una de ellas contiene una columna llamada codiArti, por tanto no es necesario calificar la tabla. Si la tabla tArticulo tambin apareciera en la clusula FROM, tendramos que calificar codiArti para evitar confusiones entre las columnas codiArti en las tablas tArticulo y tDetallePedido.
La consulta que vimos en la figura 5.16 es la ms compleja de las que hemos examinado. Esto podra hacerle pensar que, despus de todo, SQL no es un lenguaje tan sencillo. Sin embargo, si vamos paso a paso, la consulta del ejemplo 10 no es tan difcil. Para construir una consulta detallada paso a paso, haga lo siguiente: 1. Liste en la clusula SELECT todas las columnas que quiera mostrar. Si el nombre de una columna aparece en ms de una tabla, precdalo del nombre de la tabla (para calificar el nombre de la columna). 2. Liste en la clusula FROM todas las tablas que intervendrn en la consulta. Normalmente se incluyen las tablas que contienen las columnas listadas en la clusula SELECT. Sin embargo, alguna vez puede haber una tabla que no contenga ninguna de las columnas utilizadas en la clusula SELECT pero que s contiene columnas utilizadas en la clusula
88
Asignatura: Sistemas de Base de Datos WHERE. En este caso, tambin tenemos que listar la tabla en la clusula FROM. Por ejemplo, si no necesitamos listar el cdigo y nombre del cliente, pero s tenemos que listar el nombre de vendedor, no incluiramos ninguna columna de la tabla tCliente en la clusula SELECT. Sin embargo, la tabla tCliente sigue siendo necesaria, porque hay que incluir una columna suya en la clusula WHERE. 3. Tome un par de tabla relacionadas a la vez e indique en la clusula WHERE la condicin que relaciona a las tablas. Una esas condiciones con el operador AND. Si hay alguna otra condicin, inclyala en la clusula WHERE y conctelas con las otras condiciones con el operador AND. Por ejemplo, si quiere ver artculos presentes en pedidos ordenados por solo aquellos clientes con lmites de crdito de 10000, tendra que aadir una condicin adicional a la clusula WHERE, como vemos en la figura 5.17.
SELECT codiArti, cantiArti, tPedido.codiPedi, fechaPedi, tCliente.codiClien, nombreClien, apeVende FROM tVendedor, tCliente, tPedido, tDetallePedido WHERE tVendedor.codiVende = tCliente.codiVende AND tCliente.codiClien = tPedido.codiClien AND tPedido.codiPedi = tDetallePedido.codiPedi AND limiCreClien = 10000;
89