Capitulo 4 – Lección 2: Implementando SubConsultas

Las Subconsultas le permiten anidar una consulta dentro de otra para crear rutinas complejas, así como recuperar los conjuntos de datos que sería imposible de construir sin tener que recurrir a un proceso de varios pasos que escribe los resultados intermedios a objetos temporales.
Usted puede construir consultas con dos tipos de subconsultas: correlacionados y no correlacionados.
Una subconsulta no correlacionada es independiente de la consulta externa en el que está contenido.
Una subconsulta correlacionada depende de las referencias y columnas de la consulta externa.
Cualquier tipo de subconsulta puede retornar un escalar o varios valores. Con valores escalares subconsultas se pueden colocar en cualquier lugar dentro de una instrucción SELECT, donde los valores cero o uno se espera.
Una subconsulta con varios valores se pueden utilizar en cualquier parte de un conjunto de valores que se espera.

Subconsultas No correlacionadas
El objetivo principal de una subconsulta no correlacionados es que le permite escribir código que sea más dinámico y no requiere que el usuario conoce a todos los valores intermedios que existen actualmente en la base de datos. Por ejemplo, si desea obtener una lista de clientes que se han asignado a una región específica, primero hay que conocer la lista de ciudades o estados en los que para recuperar la lista solicitada. Sin embargo, una tabla que existen dentro de su base de datos que especifica qué ciudades o estados son asignados a una región determinada y una subconsulta no correlacionados se podrían utilizar para hacer su consulta flexible a los cambios en la manera como se organiza una región. He aquí un ejemplo de cómo podría funcionar:
SELECT a.CustomerID, a.FirstName, a.LastName, b.Address, b.City, b.StateProvince
FROM Customer.Customer a INNER JOIN Customer.CustomerAddress b
ON a.CustomerID = b.CustomerID
WHERE b.City IN (SELECT c.City FROM Customer.CityRegion c INNER JOIN Customer.Region d
ON c.RegionID = d.RegionID
WHERE d.Region = 'RegionX')
Como otro ejemplo, supongamos que usted quiere devolver todos los productos con un precio mayor que el precio de venta promedio para todos los productos. En lugar de tener que recuperar el precio de venta promedio por separado, almacenar el valor de una variable, y luego usar la variable en una segunda instrucción SELECT, puede utilizar la siguiente consulta:
SELECT a.ProductID, a.Name, a.ListPrice
FROM Production.Product a
WHERE a.ListPrice > (SELECT AVG(b.ListPrice) FROM Production.Product b)


Tablas Derivadas:
Si desea obtener una lista de empleados y el número de empleados que tienen el mismo puesto, usted puede tratar de ejecutar una consulta como la siguiente:
SELECT BusinessEntityID, JobTitle, count(*)
FROM HumanResources.Employee
GROUP BY BusinessEntityID, JobTitle
Ahora usted tiene un problema. Es necesario para calcular el número de empleados con un puesto de trabajo determinado y luego regresar una lista de empleados, junto con la cantidad de otros empleados tienen el mismo cargo. Sin embargo, para cumplir con los requisitos de la GROUP BY, usted tiene que incluir todas las columnas no agregada de la cláusula GROUP BY. Se enfrenta a un dilema, porque parece que la consulta no puede ser satisfecha. El problema con la consulta es el orden de las operaciones. Usted tiene que calcular en primer lugar el número de personas con un puesto de trabajo determinado.Luego, en base a ese resultado, unirlo a la tabla de los empleados para obtener una lista de los empleados y cómo muchos otros empleados tienen el mismo puesto.
En lugar de recurrir a las tablas temporales para almacenar el conjunto de resultados intermedios, T-SQL puede resolver este dilema mediante el aprovechamiento de una característica interesante de una cláusula FROM, es decir, acepta un origen de una tabla. Una tabla se construye de filas y columnas. Cuando se ejecuta una sentencia SELECT, se obtiene un conjunto de resultados que se compone de filas y columnas. Por lo tanto, parece posible que en realidad se podría incluir una instrucción SELECT en toda la cláusula FROM, porque el único requisito es disponer de una fuente que tiene la estructura de una tabla.
Al incrustar una instrucción SELECT en una cláusula FROM, se utiliza una característica conocida como tablas derivadas o tablas virtuales. Una instrucción SELECT devuelve un conjunto de resultados, pero no existe nombre para el conjunto de resultados que se hace referencia en una consulta. Usted puede evitar la necesidad de un nombre, envolviendo toda la sentencia SELECT entre paréntesis y la especificación de un alias. La solución a su problema original se convierte entonces en lo siguiente:
SELECT b.BusinessEntityID, b.JobTitle, a.numtitles
FROM (SELECT JobTitle, count(*) numtitles
FROM HumanResources.Employee
GROUP BY JobTitle) a
INNER JOIN HumanResources.Employee b ON a.JobTitle = b.JobTitle
SQL Server primero se ejecuta el SELECT ... GROUP BY, cargando los resultados en la memoria, y "etiquetas" de los resultados con el alias especificado. A continuación, puede hacer referencia a cualquier columna de la tabla derivada en el resto de la instrucción SELECT como si estuviera trabajando con una tabla física.Tenga en cuenta que cualquier agregado, concatenación, o computación en la tabla derivada debe tener un alias especificado, ya que no es posible construir una tabla con una columna que no tiene nombre.
La ventaja principal de una tabla derivada es el hecho de que el conjunto de resultados reside completamente en la memoria, lo que permite el acceso a los datos que si el conjunto de resultados se encontraban en un dispositivo de almacenamiento.
En casi todos los casos, cualquier rutina que utiliza una tabla temporal para almacenar un conjunto de resultados intermedios que se utiliza en una consulta posterior se puede utilizar una tabla derivada en su lugar.


Ejecutando consultas de valores agregados:
Mediante la combinación de tablas derivadas con desiguales JOINS, se puede calcular una variedad de agregados acumulativos. La consulta siguiente devuelve un agregado actualizado de pedidos de cada vendedor:
SELECT SH3.SalesPersonID, SH3.OrderDate, SH3.DailyTotal, SUM(SH4.DailyTotal) RunningTotal
FROM (SELECT SH1.SalesPersonID, SH1.OrderDate, SUM(SH1.TotalDue) DailyTotal
FROM Sales.SalesOrderHeader SH1
   WHERE SH1.SalesPersonID IS NOT NULL
   GROUP BY SH1.SalesPersonID, SH1.OrderDate) SH3
   INNER JOIN (SELECT SH2.SalesPersonID, SH2.OrderDate, SUM(SH2.TotalDue) DailyTotal
FROM Sales.SalesOrderHeader SH2
   WHERE SH2.SalesPersonID IS NOT NULL
   GROUP BY SH2.SalesPersonID, SH2.OrderDate) SH4
   ON SH3.SalesPersonID = SH4.SalesPersonID
   AND SH3.OrderDate >= SH4.OrderDate
   GROUP BY SH3.SalesPersonID, SH3.OrderDate, SH3.DailyTotal
ORDER BY SH3.SalesPersonID, SH3.OrderDate
Las tablas derivadas se utilizan para combinar todos los pedidos de los vendedores que tienen más de un pedido en un solo día. La combinación en SalesPersonID asegura que se están acumulando las filas de sólo un vendedor único. El join desigual permite el agregado para considerar sólo las filas de un vendedor en la fecha del pedido es anterior a la fecha de la orden está examinando actualmente en el conjunto de resultados. Mediante la adición de una cláusula HAVING, se puede ampliar un agregado actualizado para incluir una variedad de situaciones, por ejemplo, mostrar un total acumulado de ventas sólo para los vendedores que ya han cumplido con sus cuotas o ventas totales a través de una ventana deslizante.

Subconsultas correlacionadas
En una subconsulta correlacionada, la consulta interna depende de los valores de la consulta externa. Esto hace que la consulta interna para ejecutar repetidamente una función de la entrada de la consulta externa. La siguiente consulta devuelve los productos y su precio de lista correspondiente para todos los productos que se han vendido:
SELECT a.ProductID, a.ListPrice
FROM Production.Product a
WHERE EXISTS (SELECT 1 FROM Sales.SalesOrderDetail b
WHERE b.ProductID = a.ProductID)
Mediante un Join o de cualquier otra cláusula WHERE sería la devolución del producto cada vez que se vendieron, sin embargo, detallara las veces que un producto se vendió en lugar de detallar los productos que se han vendido al menos una vez. El argumento EXISTS también mejora el rendimiento de la consulta ya que SQL Server tiene que encontrar sólo una sola aparición en la tabla de la cláusula WHERE para ser verdad. Tan pronto como un valor se encuentra, SQL Server deja de mirar el resto de las filas, porque el valor de retorno no iba a cambiar a partir de ese momento.

Resumen de la lección:
  • Subconsultas no correlacionadas: son consultas independientes que están incrustados dentro de una consulta externa y se utilizan para recuperar un valor escalar o lista de valores que pueden ser consumidos por la consulta externa para que el código sea más dinámico.
  • Subconsultas correlacionadas: son las consultas que se inscriben en una consulta externa, pero los valores de referencia en la consulta externa.

No hay comentarios:

Publicar un comentario