You are on page 1of 18

Curso de SQL Server 2008 - Quinta Parte: Combinando tablas relacionadas

Autor: DesarrollandoSoftware.com Tutorial HTML En bases de datos normalizadas la informacin requerida para una consulta puede localizarse en dos o ms tablas dentro de la base de datos, ahora veremos cmo escribir consultas que usen los operadores INNER, OUTER, FULL y CROSS JOIN, tambin explicaremos la diferencia entre los diferentes operadores JOIN o de combinacin. Para esto continuaremos utilizando el Editor de consultas del Microsoft Management Studio, y las bases de datos Northwind y AdventureWorks.

Combinando tablas relacionadas El operador INNER JOIN El operador OUTER JOIN El operador SELF JOIN

Uniendo tablas relacionadas


El operador JOIN (Unin o combinacin) Los operadores JOIN permiten retornar datos de columnas almacenadas en mltiples tablas relacionadas. Como las relaciones son creadas a partir de un PRIMARY KEY (Llave primaria) y un FOREIGN KEY (Llave fornea) esto quiere decir que existirn columnas repetidas en tablas relacionadas, otro aspecto que debemos tomar en cuenta es que podemos encontrar el mismo nombre de columna en varias tablas por lo que es muy aconsejable el uso de alias. Cuando se ejecutan los JOIN, SQL Server compara los valores de las columnas especificadas fila por fila entonces usa los resultados de la comparacin para combinar los valores que califican como nuevas filas. Cuando definimos una condicin JOIN necesitamos definir las columnas que uniremos o combinaremos, el tipo de combinacin y una condicin de unin. INNER JOIN es el tipo de unin por defecto cuando solo se especifica solo la palabra JOIN. Definiendo Inner Joins (Combinaciones internas). Los Inner Joins retornan solo las columnas que coincidan en la condicin de unin. Aunque un Inner Join se puede especificar en cualquiera de la clausulas FROM o WHERE, es recomendable especificar el JOIN en la clusula FROM. A partir de aqu utilizaremos las bases de datos Northwind y AdventureWorks indistintamente, para diferenciar las consultas utilizaremos la clausula USE para especificar la base de datos con la que trabajaremos. El siguiente ejemplo retorna el nombre de producto, cantidad por unidad, precio unitario de la tabla Productos, y el nombre de categora y la descripcin de la tabla Categoras en la base de datos Northwind. Primero veamos el tipo de relacin entre estas tablas, observamos que entre Productos y Categoras existe una relacin uno a varios, (no olviden que la tabla con clave externa, fornea o FK es la que esta cerca al smbolo de ocho) y el campo con el que se relacionan es: Products.CategoryID (Foreign Key) con Categories.CategoryID (Primary Key).

Ahora para la consulta en la clausula SELECT agregamos las columnas que necesitamos, las tablas junto al operador INNER JOIN que es el tipo de unin y finalmente la condicin

USE Northwind; SELECT ProductName,QuantityPerUnit, UnitPrice ,CategoryName, Description FROM dbo.Categories INNER JOIN dbo.Products ON dbo.Categories.CategoryID = dbo.Products.CategoryID;

Con el uso de alias la misma consulta quedara as:

Veamos otro ejemplo con la base de datos de AdventureWorks El siguiente ejemplo retorna los nombres y apellidos de los empleados de la tabla Person.Contact y el titulo laboral, horas enfermo y horas de vacaciones de la tabla HumanResources.Employee

USE AdventureWorks; SELECT FirstName, LastName, HumanResources.Employee.Title ,SickLeaveHours, VacationHours FROM HumanResources.Employee INNER JOIN Person.Contact ON HumanResources.Employee.ContactID = Person.Contact.ContactID;

En la consulta anterior tuvimos que especificar que la columna title que necesitamos est en la tabla Employee(HumanResources.Employee.Title) esto porque existe el mismo nombre de columna en la tabla Contact.

Como una consulta interna (INNER JOIN) fue definida, las columnas de la tabla HumanResources.Employee que no coinciden con las columnas en Person.Contact no fueron retornadas, si queremos que suceda lo contrario debemos definir una unin externa o OUTER JOIN Outer Joins (Combinaciones externas) Cuando realizamos una combinacin interna los resultados son aquellos que coinciden en ambos campos de la condicin, eliminado aquellas que no coincidan en ambas filas o campos, en el ejemplo anterior en la tabla Person.Contact existen casi 20.000 filas o registros pero necesitbamos filtrar solo a los contactos que sean empleados, 290 registros en total. Una combinacin externa (Outer Join) devuelve una o todas las filas de una de las tablas mencionadas en la clusula FROM, junto a esta clausula debemos utilizar, siempre, ciertos operadores para definir las filas devolver la consulta, los operadores son LEFT, con este se recuperarn las filas de la tabla izquierda a la que se haya hecho referencia, con RIGHT las filas de la tabla derecha a la que se haya hecho referencia sern devueltos y con el operador FULL, se devuelven todas las filas. Veamos el anterior ejemplo con una modificacin utilizando una combinacin externa

USE AdventureWorks; SELECT FirstName, LastName, HumanResources.Employee.Title ,SickLeaveHours, VacationHours FROM HumanResources.Employee RIGHT OUTER JOIN Person.Contact ON HumanResources.Employee.ContactID = Person.Contact.ContactID ORDER BY FirstName;

El resultado de esta consulta ser todos los contactos (tabla a la derecha) y para los que sean empleados obtendremos su titulo laboral, horas enfermo y horas de vacaciones, si cambiamos por ejemplo el operador RIGHT por LEFT obtendremos solo los nombres de los empleados, intntalo. Como se vio en el ejemplo la sintaxis de una combinacin externa es operador OUTER JOIN pero tambin podemos escribir sin la palabra OUTER, solo LEFT JOIN, por ejemplo. Trabajando con ms de dos tablas Podemos unir ms de dos tablas para acceder las columnas requeridas para alguna consulta. Una recomendacin general de rendimiento es limitar en lo posible el nmero de tablas que participan en el JOIN porque SQL Server se tomara ms tiempo en resolver la consulta. El tipo ms comn de JOIN para ms de dos tablas es el INNER JOIN, el siguiente cdigo devuelve el nombre de producto (tabla Products), el precio por producto (tabla Products), el nombre a la categora que pertenece (tabla Categories), una descripcin de esta categora (tabla Categories), la compaa proveedora (tabla Suppliers) y la ciudad del proveedor (tabla Suppliers), de la base de datos Northwind. Como vemos en el diagrama, las tablas estn relacionadas de la siguiente forma: Products.CategoryID (FK) con Categories.CategoryID (PK) Products.SupplierID (FK) con Suppliers.SupplierID (PK)

Entonces la consulta vendra a ser:

USE Northwind; SELECT ProductName AS [Nombre del Producto] ,UnitPrice AS [Precio del producto] ,CategoryName AS [Categoria] ,"Description" AS [Descripcion de categoria] ,CompanyName AS [Proveedor] ,City AS [Ciudad del proveedor] FROM dbo.Products P INNER JOIN dbo.Categories C ON P.CategoryID = C.CategoryID

INNER JOIN dbo.Suppliers S ON P.SupplierID = S.SupplierID;

Noten que cuando no utilizamos la palabra reservada AS tomar la siguiente palabra o cadena entre corchetes como el alias, tambin observen que en Description agregamos una comillas esto para evitar el error de Nombre de columna no vlido, producido cuando el SQL no lo reconoce como campo. Ahora veamos un ejemplo con la base de datos AdventureWorks, Ahora necesitamos retornar los nombres y apellidos de los empleados de la tabla Person.Contact, el titulo laboral, horas enfermo y horas de vacaciones de la tabla HumanResources.Employee y la direccin de los empleados de la tabla Person.Address, veamos el diagrama de relaciones:

Al ver el diagrama de tablas vemos que la direccin que necesitamos se encuentra en la tabla Person.Address la que no esta relacionada directamente con la tabla HumanResources.Employee, pero la tabla HumanResources.EmployeeAddress relaciona ambas, veamos como generar la consulta:

USE AdventureWorks; SELECT FirstName, LastName ,HumanResources.Employee.Title, SickLeaveHours, VacationHours ,AddressLine1 FROM HumanResources.Employee INNER JOIN Person.Contact ON HumanResources.Employee.ContactID = Person.Contact.ContactID INNER JOIN HumanResources.EmployeeAddress ON HumanResources.Employee.EmployeeID = HumanResources.EmployeeAddress.EmployeeID INNER JOIN Person."Address" ON HumanResources.EmployeeAddress.AddressID = Person."Address".AddressID;

El resultado contendrn las filas deseadas utilizando tres combinaciones internas, tambin agregamos comentarios que como seguro ya lo notaron tiene la forma -- Comentario Utilizando un Self-Join Una self-join o auto-combinacin es cuando se realiza una consulta a la tabla es referenciada, esto se consigue utilizando un alias diferente cada vez que referenciamos la tabla. Veamos por ejemplo la tabla Employee,en la base de datos AdventureWorks, en esta tabla existe una columna llamada ManagerID, con esta columna podemos saber quien es el superior de cada empleado, ahora lo que queremos es saber quien es el Supervisor de cada empleado, para esto utilizaremos una auto-combinacin, veamos:

USE AdventureWorks SELECT E.EmployeeID, E.Title, M.ManagerID FROM HumanResources.Employee E INNER JOIN HumanResources.Employee M

ON E.ManagerID = M.EmployeeID ORDER BY ManagerID;

Ahora para que nuestra consulta sea ms completa la combinaremos con la tabla Contact para obtener el nombre del empleado y el nombre del supervisor

USE AdventureWorks SELECT P.FirstName + ' ' + P.LastName AS 'Nombre del Empleado' , E.Title AS 'Cargo del empleado' , MP.FirstName + ' ' + MP.LastName AS 'Nombre de Supervisor' , M.Title AS 'Cargo del Supervisor' FROM HumanResources.Employee E INNER JOIN HumanResources.Employee M ON E.ManagerID = M.EmployeeID INNER JOIN Person.Contact P

ON E.ContactID = P.ContactID INNER JOIN Person.Contact MP ON M.ContactID = MP.ContactID ORDER BY [Cargo del Supervisor];

Alguien se preguntara porque solo tenemos 289 filas como resultado si es que tenemos 290 empleados, el empleado que falta es el Director ejecutivo (Chief executive officer) que como imaginaran no tiene supervisor por tanto en la columna ManagerID tiene como dato NULL y en la condicin no especificamos que podra existir un valor NULL, para solucionar esto podramos agregar a la condicin del primer JOIN el operador lgico AND quedando:

ON E.ManagerID = M.EmployeeID OR E.ManagerID = NULL


Con lo que obtendremos todos los empleados y sus supervisores, si prueban esta modificacin observaran que Ken Snchez (Director ejecutivo) es supervisor de todos los empleados.

Para terminar esta entrega del curso hagamos unos ejercicios: EJERCICIOS 1. Escriba y ejecute un cdigo para retornar informacin de la tabla Productos donde el nombre de producto coincida con Queso, use la base de datos Northwind

USE Northwind; SELECT ProductID, CategoryID, ProductName AS [Nombre de Producto] FROM dbo.Products WHERE ProductName LIKE '%Queso%';

Note que en el resultado est incluido el ID de categora pero no el nombre de la categora, ahora en la consulta siguiente escriba y ejecute un cdigo para unir la tabla Productos con la tabla Categoras para recuperar la informacin del nombre de la categora al que pertenece el producto. Puede utilizar una consulta INNER JOIN porque est buscando solo las filas que sean iguales en ambas tablas.

USE Northwind; SElECT ProductID, dbo.Categories.CategoryID, ProductName AS [Nombre de Producto] , CategoryName [Categoria del Producto] FROM dbo.Products INNER JOIN dbo.Categories

ON dbo.Products.CategoryID = dbo.Categories.CategoryID WHERE ProductName LIKE '%Queso%';

Ntese que en la clusula SELECT al momento de indicar la columna CategoryID tuvimos que agregar la tabla a la que pertenece dbo.Categories.CategoryID, esto lo hacemos porque caso contrario SQL no sabr de cul de las tablas tomar la informacin si de Productos o de Categoras y lo interpretara como una ambiguedad. 2. De la base de datos AdventureWorks ejecute un comando que retorne informacin de la tabla ProductSubcategory donde los nombres de subcategorias contengan la palabra bike

USE AdventureWorks; SELECT ProductSubcategoryID, ProductCategoryID ,Name AS 'Nombre de Subcategoria' FROM Production.ProductSubcategory WHERE Name LIKE '%Bike%' ORDER BY [Nombre de Subcategoria];

En la consulta anterior logramos obtener ProductCategoryID pero no el nombre de la Categora, ahora ejecutemos una consulta para combinar la tabla ProductCategory con la tabla ProductSubcategory, para obtener el nombre de categora.

USE AdventureWorks; SELECT ProductSubcategoryID, Production.ProductCategory.ProductCategoryID ,Production.ProductSubcategory.Name AS 'Nombre de Subcategoria' ,Production.ProductCategory.Name AS 'Nombre de Categoria' FROM Production.ProductSubcategory INNER JOIN Production.ProductCategory ON Production.ProductCategory.ProductCategoryID = Production.ProductSubcategory.ProductCategoryID WHERE Production.ProductSubcategory.Name LIKE '%Bike%' ORDER BY [Nombre de Categoria];

Ahora aade la tabla Products para ver que productos existen en cada una de esas subcategorias

USE AdventureWorks; SELECT P.ProductID AS 'ID de Producto' ,PSC.ProductSubcategoryID AS 'ID de Subcategoria' ,PC.ProductCategoryID AS 'ID de Categoria' ,P.Name AS 'Nombre de Producto' ,PSC.Name AS 'Nombre de Subcategoria' ,PC.Name AS 'Nombre de Categoria' FROM Production.ProductSubcategory AS PSC INNER JOIN Production.ProductCategory AS PC ON PC.ProductCategoryID = PSC.ProductCategoryID INNER JOIN Production.Product AS P ON P.ProductSubcategoryID = PSC.ProductSubcategoryID WHERE PSC.Name LIKE '%Bike%' ORDER BY [Nombre de Subcategoria] ;

Una vez ms, se utiliza una combinacin interna, porque slo las filas en comn entre las tres tablas necesitan ser recuperados Resumen Cuando se utilizan JOIN se deben tomar en cuenta algunas consideraciones: - Especificar las condiciones del JOIN en base a Primary Key (PK) y a Foreign Key (FK) - Si una tabla tiene una PK compuesta, se debe referenciar a la clave entera en la clusula ON del JOIN - Las tablas comunes a las tablas deben ser del mismo tipo de dato - La clusula JOIN permite recuperar columnas de tablas relacionadas - Los operadores JOIN pueden combinar ms de una tabla. - JOIN puede incluir INNER, LEFT OUTER, RIGHT OUTER y FULL OUTER - Una tabla puede ser combinada consigo misma definiendo diferentes alias

You might also like