{"id":319,"date":"2023-09-03T17:36:14","date_gmt":"2023-09-03T15:36:14","guid":{"rendered":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/?page_id=319"},"modified":"2025-03-09T18:09:49","modified_gmt":"2025-03-09T16:09:49","slug":"1-10-consultas-avanzadas-consultas-multitabla","status":"publish","type":"page","link":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/1-10-consultas-avanzadas-consultas-multitabla\/","title":{"rendered":"1.10. Consultas avanzadas: consultas multitabla"},"content":{"rendered":"<p>Para aprovechar al m\u00e1ximo el modelo relacional y generar nuevo conocimiento de los datos existentes resulta esencial combinar informaci\u00f3n de varias tablas. Mediante un atributo que dos tablas posean en com\u00fan, esta operaci\u00f3n resulta extremadamente sencilla con SQL. Mientras efectuamos una consulta con el comando <code>SELECT<\/code>, debemos emplear la cl\u00e1usula <strong><code>JOIN<\/code><\/strong> especificando el atributo compartido por ambas tablas. Cuando se referencian atributos de dos o m\u00e1s tablas en la misma consulta, es necesario utilizar la sintaxis <code>nombre_tabla.nombre_atributo<\/code> para especificar claramente el origen de cada atributo. Es posible a\u00f1adir condiciones sobre otros atributos de las tablas con la cl\u00e1usula <strong><code>WHERE<\/code><\/strong>.<\/p>\n<p>Dadas dos tablas que denominaremos <strong>tabla1 <\/strong>y <strong>tabla2<\/strong>, que poseen un atributo comparable (<strong>tabla1.x<\/strong> y<strong> tabla2.y<\/strong>), la sintaxis del comando <strong><code>JOIN<\/code><\/strong> para obtener tanto los valores en com\u00fan como los valores presentes exclusivamente en la primera o en la segunda tabla, respectivamente, es la siguiente:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">SELECT tabla1.x,tabla2.y\r\nFROM tabla1 JOIN tabla2\r\nON tabla1.x=tabla2.y\r\nWHERE condiciones;\r\n----------------------------------------\r\nSELECT tabla1.x,tabla2.y\r\nFROM tabla1 LEFT JOIN tabla2\r\nON tabla1.x=tabla2.y\r\nWHERE condiciones;\r\n----------------------------------------\r\nSELECT tabla1.x,tabla2.y\r\nFROM tabla1 RIGHT JOIN tabla2\r\nON tabla1.x=tabla2.y\r\nWHERE condiciones;<\/pre>\n<div class=\"featured featured-blue\"><p>Para trabajar con m\u00e1s de dos tablas, podemos generalizar la misma sintaxis (por ejemplo, <code>tabla1 JOIN<\/code> (<code>tabla2,3,4<\/code>)).<\/p>\n<\/div>\n<p>Antes de proceder a ejecutar consultas sobre las tablas de la base de datos <strong>catalogo<\/strong>, proponemos poner a prueba el funcionamiento de la cl\u00e1usula <strong><code>JOIN<\/code><\/strong> sobre un ejemplo m\u00e1s simple.<\/p>\n<p>Vamos a generar dos tablas que denominaremos <strong>tabla1 <\/strong>y <strong>tabla2<\/strong>, con un \u00fanico atributo. Posteriormente, poblaremos ambas tablas con una serie de valores tales que resultar\u00e1 muy sencillo mostrar el conjunto completo de combinaciones a la hora de comparar las dos tablas.<\/p>\n<p>Primero procedemos a crear las dos tablas:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"mowtwo\">mysql&gt; CREATE TABLE tabla1\r\n    -&gt; (x VARCHAR(10));\r\n\r\nQuery OK, 0 rows affected (0.5 sec)\r\n\r\nmysql&gt; CREATE TABLE tabla2\r\n     -&gt; (y VARCHAR(10));\r\n\r\nQuery OK, 0 rows affected (0.5 sec)<\/pre>\n<div class=\"featured featured-blue\"><p>Os animamos a reproducir en vuestro ordenador los comandos de SQL presentados en este apartado.<\/p>\n<\/div>\n<p>Ahora vamos a crear dos sencillos ficheros de texto con tres valores cada uno: (1,2,3) y (3,4,5). De este modo, vamos a poder estudiar detalladamente la clase de consulta de MySQL que necesitamos para recuperar los valores comunes entre ambas tablas (3) o, alternativamente, los valores que \u00fanicamente aparecen en la primera (1 y 2) o en la segunda tabla (4 y 5).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"droide\">1\r\n2\r\n3\r\n\r\n---------------------------------------------\r\n\r\n3\r\n4\r\n5<\/pre>\n<p>Finalmente, poblamos las dos tablas utilizando ambos ficheros:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"mowtwo\">mysql&gt; LOAD DATA LOCAL INFILE 'datos1.txt' INTO TABLE tabla1;\r\n\r\nQuery OK, 3 rows affected (0.67 sec)\r\nRecords: 3  Deleted: 0  Skipped: 0  Warnings: 0\r\n\r\nmysql&gt; LOAD DATA LOCAL INFILE 'datos2.txt' INTO TABLE tabla2;\r\n\r\nQuery OK, 3 rows affected (0.43 sec)\r\nRecords: 3  Deleted: 0  Skipped: 0  Warnings: 0<\/pre>\n<p>Ya estamos en disposici\u00f3n de profundizar en el funcionamiento de las consultas que incluyen la cl\u00e1usula <strong><code>JOIN<\/code><\/strong>. Si no a\u00f1adimos ninguna opci\u00f3n, este comando genera todas las parejas posibles cuyo primer elemento pertenece a la primera tabla y el segundo elemento pertenece a la segunda:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"mowtwo\">mysql&gt; SELECT tabla1.x,tabla2.y\r\n    -&gt; FROM tabla1 JOIN tabla2;\r\n\r\n+-----+-----+\r\n| x   | y   |\r\n+-----+-----+\r\n| 1   | 3   |\r\n| 2   | 3   |\r\n| 3   | 3   |\r\n| 1   | 4   |\r\n| 2   | 4   |\r\n| 3   | 4   |\r\n| 1   | 5   |\r\n| 2   | 5   |\r\n| 3   | 5   |\r\n+-----+-----+\r\n9 rows in set (0.00 sec)<\/pre>\n<p>Nuestro primer objetivo en una comparaci\u00f3n es localizar los elementos comunes. Para ello es suficiente con incorporar la cl\u00e1usula <strong><code>ON<\/code><\/strong> a la consulta y especificar el atributo compartido por las dos tablas. Esto filtrar\u00e1 aquellas parejas del resultado anterior que no cumplan esta propiedad, mostr\u00e1ndose aquello que busc\u00e1bamos:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"mowtwo\">mysql&gt; SELECT tabla1.x,tabla2.y\r\n    -&gt; FROM tabla1 JOIN tabla2\r\n    -&gt; ON tabla1.x=tabla2.y;\r\n\r\n+-----+-----+\r\n| x   | y   |\r\n+-----+-----+\r\n| 3   | 3   |\r\n+-----+-----+\r\n1 row in set (0.00 sec)<\/pre>\n<p>En determinados casos, en lugar de la lista de los valores comunes, estaremos interesados tambi\u00e9n en aquellos valores de una u otra tabla que no pertenecen a la otra. Para ello debemos modificar el comportamiento del comando <code>JOIN<\/code> con las cl\u00e1usulas <strong><code>LEFT<\/code><\/strong> o <strong><code>RIGHT<\/code><\/strong>. Si realizamos una uni\u00f3n por la parte izquierda, recuperaremos un listado de los registros de la primera tabla junto con su registro equivalente en la segunda. En el caso de que este valor an\u00e1logo no existiera, MySQL lo indicar\u00e1 con el valor <code>NULL<\/code>. Si, por el contrario, realizamos la uni\u00f3n por la derecha, obtendremos un listado de los valores de la segunda tabla bajo las mismas condiciones.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"mowtwo\">mysql&gt; SELECT tabla1.x,tabla2.y\r\n    -&gt; FROM tabla1 LEFT JOIN tabla2\r\n    -&gt; ON tabla1.x=tabla2.y;\r\n\r\n+-----+------+\r\n| x   | y    |\r\n+-----+------+\r\n| 3   | 3    |\r\n| 1   | NULL |\r\n| 2   | NULL |\r\n+-----+------+\r\n3 rows in set (0.00 sec)\r\n\r\nmysql&gt; SELECT tabla1.x,tabla2.y\r\n    -&gt; FROM tabla1 RIGHT JOIN tabla2\r\n    -&gt; ON tabla1.x=tabla2.y;\r\n\r\n+------+-----+\r\n| x    | y   |\r\n+------+-----+\r\n| 3    | 3   |\r\n| NULL | 4   |\r\n| NULL | 5   |\r\n+------+-----+\r\n3 rows in set (0.00 sec)<\/pre>\n<p>Para acabar de refinar el resultado, debemos mantener exclusivamente los valores que solo est\u00e1n en una tabla. Para lograrlo, podemos a\u00f1adir al final de la consulta una condici\u00f3n <code>WHERE<\/code> que exija que el valor no est\u00e9 presente en la otra tabla. La cl\u00e1usula <code>IS<\/code> realiza la evaluaci\u00f3n de la expresi\u00f3n que se encuentra a continuaci\u00f3n, para acabar respondiendo con un valor booleano (cierto o falso).<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\" data-enlighter-theme=\"mowtwo\">mysql&gt; SELECT tabla1.x,tabla2.y\r\n    -&gt; FROM tabla1 LEFT JOIN tabla2\r\n    -&gt; ON tabla1.x=tabla2.y\r\n    -&gt; WHERE tabla2.y IS NULL;\r\n\r\n+-----+------+\r\n| x   | y    |\r\n+-----+------+\r\n| 1   | NULL |\r\n| 2   | NULL |\r\n+-----+------+\r\n2 rows in set (0.00 sec)\r\n\r\nmysql&gt; SELECT tabla1.x,tabla2.y\r\n    -&gt; FROM tabla1 RIGHT JOIN tabla2\r\n    -&gt; ON tabla1.x=tabla2.y\r\n    -&gt; WHERE tabla1.x IS NULL;\r\n\r\n+------+-----+\r\n| x    | y   |\r\n+------+-----+\r\n| NULL | 4   |\r\n| NULL | 5   |\r\n+------+-----+\r\n2 rows in set (0.00 sec)<\/pre>\n<p>Ahora ya estamos en condiciones de efectuar consultas sobre dos o m\u00e1s tablas de nuestro cat\u00e1logo de genes. Por ejemplo, podemos preguntar por aquellos genes humanos para los cuales se ha documentado una anotaci\u00f3n funcional de car\u00e1cter experimental:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">mysql&gt; SELECT genes.nombre,genes.especie,\r\n    -&gt; anotaciones.funcion,anotaciones.origen\r\n    -&gt; FROM genes JOIN anotaciones\r\n    -&gt; ON genes.nombre=anotaciones.nombre\r\n    -&gt; WHERE anotaciones.origen='experimental'\r\n    -&gt; AND genes.especie='H. sapiens';\r\n\r\n+--------+------------+------------+--------------+\r\n| nombre |   especie  |  funcion   |    origen    |\r\n+--------+------------+------------+--------------+\r\n| HNF1A  | H. sapiens | GO:0003700 | Experimental |\r\n| MYC    | H. sapiens | GO:0003700 | Experimental |\r\n+--------+------------+------------+--------------+\r\n2 rows in set (0.00 sec)<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Para aprovechar al m\u00e1ximo el modelo relacional y generar nuevo conocimiento de los datos existentes resulta esencial combinar informaci\u00f3n de varias tablas. Mediante un atributo que dos tablas posean en com\u00fan, esta operaci\u00f3n resulta extremadamente sencilla con SQL. Mientras efectuamos una consulta con el comando SELECT, debemos emplear la cl\u00e1usula JOIN especificando el atributo compartido [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"acf":[],"_links":{"self":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/pages\/319"}],"collection":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/comments?post=319"}],"version-history":[{"count":7,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/pages\/319\/revisions"}],"predecessor-version":[{"id":1013,"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/pages\/319\/revisions\/1013"}],"wp:attachment":[{"href":"http:\/\/eines-informatiques.recursos.uoc.edu\/gestion-de-datos\/es\/wp-json\/wp\/v2\/media?parent=319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}