AnteriorPosterior

10. Subconsultas

  Curso: Curso de SQL, por Claudio Casares

Subconsultas


[Curso de SQL - Por Claudio Casares]

Una subconsulta es una instrucción SELECT anidada dentro de una instrucción SELECT, SELECT...INTO, INSERT...INTO, DELETE, o UPDATE o dentro de otra subconsulta. Puede utilizar tres formas de sintaxis para crear una subconsulta:


comparación [ANY | ALL | SOME] (instrucción sql)
expresión [NOT] IN (instrucción sql)
[NOT] EXISTS (instrucción sql)

En donde:

comparaciónEs una expresión y un operador de comparación que compara la expresión con el resultado de la subconsulta.
expresiónEs una expresión por la que se busca el conjunto resultante de la subconsulta.
instrucción SQLEs una instrucción SELECT, que sigue el mismo formato y reglas que cualquier otra instrucción SELECT. Debe ir entre paréntesis.

Se puede utilizar una subconsulta en lugar de una expresión en la lista de campos de una instrucción SELECT o en una cláusula WHERE o HAVING. En una subconsulta, se utiliza una instrucción SELECT para proporcionar un conjunto de uno o más valores especificados para evaluar en la expresión de la cláusula WHERE o HAVING.

Se puede utilizar el predicado ANY o SOME, los cuales son sinónimos, para recuperar registros de la consulta principal, que satisfagan la comparación con cualquier otro registro recuperado en la subconsulta. El ejemplo siguiente devuelve todos los productos cuyo precio unitario es mayor que el de cualquier producto vendido con un descuento igual o mayor al 25 por ciento:

SELECT *
FROM
Productos
WHERE
PrecioUnidad

ANY

(

SELECT

PrecioUnidad

FROM

DetallePedido

WHERE

Descuento = 0 .25

)

El predicado ALL se utiliza para recuperar únicamente aquellos registros de la consulta principal que satisfacen la comparación con todos los registros recuperados en la subconsulta. Si se cambia ANY por ALL en el ejemplo anterior, la consulta devolverá únicamente aquellos productos cuyo precio unitario sea mayor que el de todos los productos vendidos con un descuento igual o mayor al 25 por ciento. Esto es mucho más restrictivo.

El predicado IN se emplea para recuperar únicamente aquellos registros de la consulta principal para los que algunos registros de la subconsulta contienen un valor igual. El ejemplo siguiente devuelve todos los productos vendidos con un descuento igual o mayor al 25 por ciento:

SELECT *
FROM
Productos
WHERE
IDProducto

IN

(

SELECT

IDProducto

FROM

DetallePedido

WHERE

Descuento = 0.25

)

Inversamente se puede utilizar NOT IN para recuperar únicamente aquellos registros de la consulta principal para los que no hay ningún registro de la subconsulta que contenga un valor igual.

El predicado EXISTS (con la palabra reservada NOT opcional) se utiliza en comparaciones de verdad/falso para determinar si la subconsulta devuelve algún registro. Supongamos que deseamos recuperar todos aquellos clientes que hayan realizado al menos un pedido:

SELECT
Clientes.Compañía, Clientes.Teléfono
FROM

Clientes
WHERE EXISTS (

SELECT

FROM

Pedidos

WHERE

Pedidos.IdPedido = Clientes.IdCliente
)

Esta consulta es equivalente a esta otra:

SELECT
Clientes.Compañía, Clientes.Teléfono
FROM
Clientes
WHERE
IdClientes

IN

(

SELECT

Pedidos.IdCliente

FROM

Pedidos

)

Se puede utilizar también alias del nombre de la tabla en una subconsulta para referirse a tablas listadas en la cláusula FROM fuera de la subconsulta. El ejemplo siguiente devuelve los nombres de los empleados cuyo salario es igual o mayor que el salario medio de todos los empleados con el mismo título. A la tabla Empleados se le ha dado el alias T1:

SELECT
Apellido, Nombre, Titulo, Salario
FROM
Empleados AS T1
WHERE
Salario =

(

SELECT

Avg(Salario)

FROM

Empleados

WHERE

T1.Titulo = Empleados.Titulo

)
ORDER BY Titulo

En el ejemplo anterior, la palabra reservada AS es opcional.

SELECT
Apellidos, Nombre, Cargo, Salario
FROM
Empleados
WHERE
Cargo LIKE 'Agente Ven*'
AND
Salario ALL

(

SELECT

Salario

FROM

Empleados

WHERE

Cargo LIKE '*Jefe*'

OR

Cargo LIKE '*Director*'

)
(Obtiene una lista con el nombre, cargo y salario de todos los agentes de ventas cuyo salario es mayor que el de todos los jefes y directores.)
SELECT DISTINCT
NombreProducto, Precio_Unidad
FROM
Productos
WHERE
PrecioUnidad =

(

SELECT

PrecioUnidad

FROM

Productos

WHERE

NombreProducto = 'Almíbar anisado'

)
(Obtiene una lista con el nombre y el precio unitario de todos los productos con el mismo precio que el almíbar anisado.)
SELECT DISTINCT
NombreContacto, NombreCompania, CargoContacto, Telefono
FROM
Clientes
WHERE
IdCliente IN (

SELECT DISTINCT IdCliente

FROM Pedidos

WHERE FechaPedido <#07/01/1993#
)
(Obtiene una lista de las compañías y los contactos de todos los clientes que han realizado un pedido en el segundo trimestre de 1993.)
SELECT
Nombre, Apellidos
FROM
Empleados AS E
WHERE EXISTS

(

SELECT *

FROM

Pedidos AS O

WHERE O.IdEmpleado = E.IdEmpleado

)
(Selecciona el nombre de todos los empleados que han reservado al menos un pedido.)
SELECT DISTINCT
Pedidos.Id_Producto, Pedidos.Cantidad,

(

SELECT

Productos.Nombre

FROM

Productos

WHERE

Productos.IdProducto = Pedidos.IdProducto

) AS ElProducto
FROM
Pedidos
WHERE
Pedidos.Cantidad = 150
ORDER BY
Pedidos.Id_Producto
(Recupera el Código del Producto y la Cantidad pedida de la tabla pedidos, extrayendo el nombre del producto de la tabla de productos.)
SELECT
NumVuelo, Plazas
FROM
Vuelos
WHERE
Origen = 'Madrid'
AND Exists (
SELECT T1.NumVuelo FROM Vuelos AS T1
WHERE T1.PlazasLibres > 0 AND T1.NumVuelo=Vuelos.NumVuelo
)
(Recupera números de vuelo y capacidades de aquellos vuelos con destino Madrid y plazas libres

Supongamos ahora que tenemos una tabla con los identificadores de todos nuestros productos y el stock de cada uno de ellos. En otra tabla se encuentran todos los pedidos que tenemos pendientes de servir. Se trata de averiguar que productos no se podemos servir por falta de stock.

SELECT
PedidosPendientes.Nombre
FROM
PedidosPendientes
GROUP BY
PedidosPendientes.Nombre
HAVING
SUM(PedidosPendientes.Cantidad <

(

SELECT

Productos.Stock

FROM

Productos

WHERE

Productos.IdProducto = PedidosPendientes.IdProducto

)
)

Supongamos que en nuestra tabla de empleados deseamos buscar todas las mujeres cuya edad sea mayor a la de cualquier hombre:

SELECT
Empleados.Nombre
FROM
Empleados
WHERE
Sexo = 'M' AND Edad > ANY
(SELECT Empleados.Edad FROM Empleados WHERE Sexo ='H'
)

ó lo que sería lo mismo:

SELECT
Empleados.Nombre
FROM
Empleados
WHERE
Sexo = 'M' AND Edad >
(SELECT Max( Empleados.Edad )FROM Empleados WHERE Sexo ='H'
)

La siguiente tabla muestra algún ejemplo del operador ANY y ALL

Valor 1 Operador Valor 2 Resultado
3 > ANY (2,5,7) Cierto
3 = ANY (2,5,7) Falso
3 = ANY (2,3,5,7) Cierto
3 > ALL (2,5,7) Falso
3 < ALL (5,6,7) Falso

El operacion =ANY es equivalente al operador IN, ambos devuelven el mismo resultado.

Para concluir este apartado comentar que: la cláusula EXISTS se puede emplear para generar la intersección entre dos consultas y, por tanto, la cláusula NOT EXISTS para generar la diferencia entre consultas.

Actualizado el: 14-03-2006 16:57

AnteriorPosterior