{"id":262,"date":"2015-08-20T07:12:42","date_gmt":"2015-08-20T07:12:42","guid":{"rendered":"https:\/\/blogs.ua.es\/jpm33\/?p=262"},"modified":"2015-08-20T07:12:42","modified_gmt":"2015-08-20T07:12:42","slug":"sql-join-cual-usar","status":"publish","type":"post","link":"https:\/\/blogs.ua.es\/jpm33\/2015\/08\/20\/sql-join-cual-usar\/","title":{"rendered":"SQL Join: \u00bfCual usar?"},"content":{"rendered":"<h1>Introducci\u00f3n<\/h1>\n<p>Hace unos d\u00edas tuve una conversaci\u00f3n muy recurrente entre desarrolladores de software respecto del uso cotidiano de SQL. \u00bfC\u00f3mo usar JOIN? Esta duda la tienen a\u00fan desarrolladores expertos, pues bien vamos a aclarar un poco que es eso del JOIN.<\/p>\n<p>Como breve resumen, decir que JOIN se usa en SQL para combinar filas de dos o m\u00e1s tablas. Y es una sentencia con tantas posibilidades que realmente se merece una explicaci\u00f3n en una \u00fanica entrada de este blog.<\/p>\n<h1>La sentencia JOIN como una expresi\u00f3n algebraica<\/h1>\n<p>Si tomamos cada tabla de la base de datos como un conjunto de datos donde cada columna posee su propio dominio definimos el operador <img decoding=\"async\" src=\"http:\/\/chart.apis.google.com\/chart?cht=tx&amp;chl=\\triangleright\\triangleleft\" alt=\"\" \/> como el JOIN para el conjunto de tuplas a relacionar (no deja de ser una composici\u00f3n):<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/chart.apis.google.com\/chart?cht=tx&amp;chl=R\\triangleright\\triangleleft%20S=\\{t\\cup%20s|%20t\\in%20R%20\\wedge%20s\\in%20S%20\\wedge%20Condition(t,%20s)\\}\" alt=\"\" \/><\/p>\n<p>De modo que R y S son dos tablas, y t y s son filas de cada tabla que se unir\u00e1n si se cumple la condici\u00f3n dada. Y lo m\u00e1s f\u00e1cil es ver el siguiente dibujo que representa los diferentes tipos de JOINS que existen conceptualmente (no todas los sistemas gestores de base de datos los soportan) y su representaci\u00f3n aproximada como diagrama de Venn:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/blogs.ua.es\/jpm33\/files\/2014\/04\/sqljoin.png\" alt=\"\" \/><\/p>\n<p>En este\u00a0dibujo podemos ver gr\u00e1ficamente la idea de cada tipo de JOIN, filas que se relacionan en ambas tablas (conjuntos), filas que no tengan relaci\u00f3n y est\u00e9n en una tabla pero s\u00ed en la otra. O al rev\u00e9s, filas que no est\u00e9n en la primera tabla y s\u00ed en la segundo, y en fin &#8230; todas las combinaciones que muestra el gr\u00e1fico.<\/p>\n<p>Por cierto, si se hace una composici\u00f3n de dos tablas con JOIN y la fila compuesta devuelta es resultado de una relaci\u00f3n donde para una tabla hay datos y en la segunda tabla no existe relaci\u00f3n, los campos de esa segunda tabla devueltos ser\u00e1m NULL.<\/p>\n<p>Para leer m\u00e1s sobre algebra relacional recomiendo los apuntes de\u00a0Pedro Pablo Alarc\u00f3n Cavero [4], buen material docente sin duda. Pero todo esto es mejor analizarlo con un buen ejemplo.<\/p>\n<h1>Caso pr\u00e1ctico<\/h1>\n<p>Si accedemos a la Web de W3Schools, tiene una base de datos de ejemplo donde podemos probar online difernetes sentencias SQL <a href=\"http:\/\/www.w3schools.com\/sql\/trysql.asp?filename=trysql_select_join\">[Acceso a la BD en W3Schools]<\/a>.<\/p>\n<h2>Tablas de datos b\u00e1sicas<\/h2>\n<p>En este apartado primero vamos a ver una muestra de los datos que contienen las tablas, en la mayor\u00eda de casos vamos a ver una SELECT y los primeros registros que devuelve\u00a0la base de datos, para mas informaci\u00f3n consultar el enlace &#8220;Acceso a la DB de W3Schools&#8221;.<\/p>\n<h3>Listado de Clientes<\/h3>\n<pre>select * from Customers\r\n<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>CustomerID<\/th>\n<th>CustomerName<\/th>\n<th>ContactName<\/th>\n<th>Address<\/th>\n<th>City<\/th>\n<th>PostalCode<\/th>\n<th>Country<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Alfreds Futterkiste<\/td>\n<td>Maria Anders<\/td>\n<td>Obere Str. 57<\/td>\n<td>Berlin<\/td>\n<td>12209<\/td>\n<td>Germany<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>Ana Trujillo Emparedados y helados<\/td>\n<td>Ana Trujillo<\/td>\n<td>Avda. de la Constituci\u00f3n 2222<\/td>\n<td>M\u00e9xico D.F.<\/td>\n<td>05021<\/td>\n<td>Mexico<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>Antonio Moreno Taquer\u00eda<\/td>\n<td>Antonio Moreno<\/td>\n<td>Mataderos 2312<\/td>\n<td>M\u00e9xico D.F.<\/td>\n<td>05023<\/td>\n<td>Mexico<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(Devuelve 91 clientes)<\/p>\n<h3>Listado de Empleados<\/h3>\n<pre>select * from Employees<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>EmployeeID<\/th>\n<th>LastName<\/th>\n<th>FirstName<\/th>\n<th>BirthDate<\/th>\n<th>Photo<\/th>\n<th>Notes<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Davolio<\/td>\n<td>Nancy<\/td>\n<td>1968-12-08<\/td>\n<td>EmpID1.pic<\/td>\n<td>Education includes a BA in psychology from Colorado State University. She also completed (The Art of the Cold Call). Nancy is a member of &#8216;Toastmasters International&#8217;.<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>Fuller<\/td>\n<td>Andrew<\/td>\n<td>1952-02-19<\/td>\n<td>EmpID2.pic<\/td>\n<td>Andrew received his BTS commercial and a Ph.D. in international marketing from the University of Dallas. He is fluent in French and Italian and reads German. He joined the company as a sales representative, was promoted to sales manager and was then named vice president of sales. Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(Devuelve 10 empleados)<\/p>\n<h3>Listado de Transportistas<\/h3>\n<pre>select * from Shippers<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>ShipperID<\/th>\n<th>ShipperName<\/th>\n<th>Phone<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Speedy Express<\/td>\n<td>(503) 555-9831<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>United Package<\/td>\n<td>(503) 555-3199<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>Federal Shipping<\/td>\n<td>(503) 555-9931<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(Devuelve 3 transportistas)<\/p>\n<h3>Listado de Pedidos<\/h3>\n<pre>select * from Orders<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>OrderID<\/th>\n<th>CustomerID<\/th>\n<th>EmployeeID<\/th>\n<th>OrderDate<\/th>\n<th>ShipperID<\/th>\n<\/tr>\n<tr>\n<td>10248<\/td>\n<td>90<\/td>\n<td>5<\/td>\n<td>1996-07-04<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<td>10249<\/td>\n<td>81<\/td>\n<td>6<\/td>\n<td>1996-07-05<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>10250<\/td>\n<td>34<\/td>\n<td>4<\/td>\n<td>1996-07-08<\/td>\n<td>2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(Devuelve 196 pedidos)<\/p>\n<h2>Obtener los pedidos de cada cliente<\/h2>\n<p>Este es el ejemplo que ofrece <b>W3SChools<\/b>:<\/p>\n<pre>SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate\r\nFROM Orders\r\nINNER JOIN Customers\r\nON Orders.CustomerID=Customers.CustomerID;<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>OrderID<\/th>\n<th>CustomerName<\/th>\n<th>OrderDate<\/th>\n<\/tr>\n<tr>\n<td>10248<\/td>\n<td>Wilman Kala<\/td>\n<td>1996-07-04<\/td>\n<\/tr>\n<tr>\n<td>10249<\/td>\n<td>Tradi\u00e7\u00e3o Hipermercados<\/td>\n<td>1996-07-05<\/td>\n<\/tr>\n<tr>\n<td>10250<\/td>\n<td>Hanari Carnes<\/td>\n<td>1996-07-08<\/td>\n<\/tr>\n<tr>\n<td>10251<\/td>\n<td>Victuailles en stock<\/td>\n<td>1996-07-08<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>(Mostramos los 4 primeros, hay 196 resultados)<\/p>\n<h2>Obtener los clientes que nunca han hecho un pedido<\/h2>\n<p>Ahora vamos a pensar en la tabla clientes y en pedidos. En pedidos se registran los pedidos y qu\u00e9 cliente lo realiza, pero &#8230; \u00bfc\u00f3mo saber qu\u00e9 clientes no han hecho a\u00fan un pedido?<\/p>\n<pre>SELECT c.CustomerID AS CodigoCliente, c.CustomerName, o.CustomerID AS ClienteEnPedido\r\nFROM Customers AS c\r\nLEFT JOIN Orders AS o ON c.CustomerID=o.CustomerID\r\nWHERE o.OrderID IS NULL;<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>CodigoCliente<\/th>\n<th>CustomerName<\/th>\n<th>ClienteEnPedido<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Alfreds Futterkiste<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>6<\/td>\n<td>Blauer See Delikatessen<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>12<\/td>\n<td>Cactus Comidas para llevar<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>22<\/td>\n<td>FISSA Fabrica Inter. Salchichas S.A.<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>26<\/td>\n<td>France restauration<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>32<\/td>\n<td>Great Lakes Food Market<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>40<\/td>\n<td>La corne d&#8217;abondance<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>42<\/td>\n<td>Laughing Bacchus Wine Cellars<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>43<\/td>\n<td>Lazy K Kountry Store<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>45<\/td>\n<td>Let&#8217;s Stop N Shop<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>50<\/td>\n<td>Maison Dewey<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>53<\/td>\n<td>North\/South<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>57<\/td>\n<td>Paris sp\u00e9cialit\u00e9s<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>64<\/td>\n<td>Rancho grande<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>74<\/td>\n<td>Sp\u00e9cialit\u00e9s du monde<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>78<\/td>\n<td>The Cracker Box<\/td>\n<td>null<\/td>\n<\/tr>\n<tr>\n<td>82<\/td>\n<td>Trail&#8217;s Head Gourmet Provisioners<\/td>\n<td>null<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>De los 91 clientes que hay, estos 17 no tiene pedidos realizados. Adem\u00e1s podemos ver c\u00f3mo la columna con el ID de cliente en pedidos obtenida con este JOIN vale NULL, con lo que sabemos que existe relaci\u00f3n.<\/p>\n<h2>Obtener los empleados que no han hecho ventas<\/h2>\n<p>Este es otro ejemplo c\u00f3mo el anterior:<\/p>\n<pre>SELECT e.EmployeeID, e.FirstName\r\nFROM Employees AS e\r\nLEFT JOIN Orders AS o ON e.EmployeeID=o.EmployeeID\r\nWHERE o.EmployeeID IS NULL;<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>EmployeeID<\/th>\n<th>LastName<\/th>\n<th>FirstName<\/th>\n<th>BirthDate<\/th>\n<th>Photo<\/th>\n<th>Notes<\/th>\n<\/tr>\n<tr>\n<td>10<\/td>\n<td>West<\/td>\n<td>Adam<\/td>\n<td>1928-09-19<\/td>\n<td>EmpID10.pic<\/td>\n<td>An old chum.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Adam West es el \u00fanico cliente que no ha registrado pedidos en la base de datos.<\/p>\n<h2>Obtener qu\u00e9 pedidos ha hecho Nancy<\/h2>\n<p>Este caso es el mismo que obtener los pedidos de cada cliente, pero a\u00f1adiendo un flltro por empleado.<\/p>\n<pre>SELECT e.EmployeeID, e.FirstName, o.OrderID\r\nFROM Employees AS e\r\nINNER JOIN Orders AS o ON e.EmployeeID=o.EmployeeID\r\nWHERE e.FirstName = 'Nancy';<\/pre>\n<table class=\"reference notranslate\">\n<tbody>\n<tr>\n<th>EmployeeID<\/th>\n<th>FirstName<\/th>\n<th>OrderID<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Nancy<\/td>\n<td>10258<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Nancy<\/td>\n<td>10270<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Nancy<\/td>\n<td>10275<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Nancy<\/td>\n<td>10285<\/td>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>Nancy<\/td>\n<td>10292<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Muestro los 5 primeros pedidos, pero Nancy ha hecho 29 pedidos.<\/p>\n<h1>Conclusi\u00f3n<\/h1>\n<p>JOIN es una clausula para las consultas SELECT que enrique mucho\u00a0el lenguaje SQL, permite realizar consultas para diferentes casos muy interesantes sin tener que recurrir a escribir consultas muy complicadas.<\/p>\n<p>Ejemplos para analizar el uso de JOIN hay muchos y en Google podemos encontrar muchos, espero que este resumen sirva de ayuda.<\/p>\n<h1>Referencias<\/h1>\n<ol>\n<li><strong>Join en Wikipedia<\/strong>: <a href=\"http:\/\/es.wikipedia.org\/wiki\/Join\" target=\"_blank\">http:\/\/es.wikipedia.org\/wiki\/Join<\/a><\/li>\n<li><strong>Join en W3SChools<\/strong>:\u00a0<a href=\"http:\/\/www.w3schools.com\/sql\/sql_join.asp\">http:\/\/www.w3schools.com\/sql\/sql_join.asp<\/a><\/li>\n<li><strong>Manual de MySQL5 &#8211; Sentencia JOIN<\/strong>: <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.0\/es\/join.html\" target=\"_blank\">http:\/\/dev.mysql.com\/doc\/refman\/5.0\/es\/join.html<\/a><\/li>\n<li><strong>Para leer algo m\u00e1s sobre algebra relacional<\/strong> (con permiso de Pedro Pablo Alarc\u00f3n Cavero ): http:\/\/www-oei.eui.upm.es\/Asignaturas\/BD\/BD\/docbd\/tema\/algebra.pdf<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Introducci\u00f3n Hace unos d\u00edas tuve una conversaci\u00f3n muy recurrente entre desarrolladores de software respecto del uso cotidiano de SQL. \u00bfC\u00f3mo usar JOIN? Esta duda la tienen a\u00fan desarrolladores expertos, pues bien vamos a aclarar un poco que es eso del &hellip; <a href=\"https:\/\/blogs.ua.es\/jpm33\/2015\/08\/20\/sql-join-cual-usar\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":3080,"featured_media":261,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[374,676,236732,236731],"tags":[236718,1839,23],"class_list":["post-262","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programacion","category-sin-categoria","category-sql","category-web","tag-programacion-2","tag-sql","tag-web"],"_links":{"self":[{"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/posts\/262","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/users\/3080"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/comments?post=262"}],"version-history":[{"count":9,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/posts\/262\/revisions"}],"predecessor-version":[{"id":311,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/posts\/262\/revisions\/311"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/media\/261"}],"wp:attachment":[{"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/media?parent=262"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/categories?post=262"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ua.es\/jpm33\/wp-json\/wp\/v2\/tags?post=262"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}