Subqueries en SQL Server: ejemplos con IN, AVG y MAX

Aprendé subqueries en SQL Server con ejemplos prácticos: ventas superiores al promedio, subconsultas con IN para delivery y cómo obtener la venta de mayor importe.

Video del curso SQL: subconsultas para comparar importes, filtrar ventas delivery y encontrar el importe máximo · Ver en YouTube

Subqueries en SQL Server: qué son y para qué sirven

Una subquery o subconsulta es una consulta SQL dentro de otra consulta. La consulta interna obtiene un dato —o una lista de datos— y la consulta externa usa ese resultado para filtrar, comparar o devolver información completa.

En este capítulo trabajamos con ventas facturadas y ventas delivery para resolver tres situaciones reales:

  • Ver las ventas cuyo importe supera el promedio general.
  • Obtener únicamente las ventas que fueron delivery usando IN.
  • Encontrar la fila completa de la venta con mayor importe usando MAX.

La ventaja principal es que las consultas se mantienen dinámicas: no dependés de copiar a mano un valor que puede cambiar cuando cambian los datos.


Tablas del ejemplo: movimientos facturados y delivery

La tabla MOVIMIENTOS_FACTURADOS concentra todas las ventas. MOVIMIENTOS_DELIVERY guarda los datos adicionales de aquellas ventas que fueron enviadas a domicilio.

CREATE TABLE MOVIMIENTOS_FACTURADOS (
  ID_MOVIMIENTO INT PRIMARY KEY,
  FECHA DATETIME NOT NULL,
  CLIENTE VARCHAR(100) NOT NULL,
  IMPORTE DECIMAL(10, 2) NOT NULL,
  MEDIO_PAGO VARCHAR(30) NOT NULL
);

CREATE TABLE MOVIMIENTOS_DELIVERY (
  ID_DELIVERY INT IDENTITY(1, 1) PRIMARY KEY,
  ID_MOVIMIENTO INT NOT NULL,
  DIRECCION VARCHAR(150) NOT NULL,
  REPARTIDOR VARCHAR(100),
  COSTO_ENVIO DECIMAL(10, 2) NOT NULL,
  ESTADO VARCHAR(30) NOT NULL,
  CONSTRAINT FK_MOVIMIENTOS_DELIVERY_FACTURADOS
    FOREIGN KEY (ID_MOVIMIENTO)
    REFERENCES MOVIMIENTOS_FACTURADOS(ID_MOVIMIENTO)
);

La columna que vincula ambas tablas es ID_MOVIMIENTO. En MOVIMIENTOS_DELIVERY funciona como foreign key: cada delivery debe corresponder a una venta facturada existente. Si querés profundizar en esa relación, revisá Primary Key y Foreign Key desde cero.

Qué es una subconsulta en SQL

Pensala como una consulta padre que contiene una consulta más pequeña. La interna se ejecuta para entregar el resultado que necesita la consulta externa.

SELECT *
FROM MOVIMIENTOS_FACTURADOS
WHERE IMPORTE > (
  SELECT AVG(IMPORTE)
  FROM MOVIMIENTOS_FACTURADOS
);

La subconsulta es este bloque:

SELECT AVG(IMPORTE)
FROM MOVIMIENTOS_FACTURADOS

Devuelve un único importe promedio. La consulta exterior toma ese resultado y devuelve cada venta cuyo IMPORTE sea superior.


Ejemplo 1: ventas que superan el importe promedio

Primero podés consultar el promedio de manera aislada para comprobar qué valor se está calculando:

SELECT AVG(IMPORTE) AS PromedioImporte
FROM MOVIMIENTOS_FACTURADOS;

Una opción sería copiar el número devuelto y escribirlo en un filtro:

SELECT *
FROM MOVIMIENTOS_FACTURADOS
WHERE IMPORTE > 1200.00;

Pero ese valor queda hardcodeado. Si actualizás un importe, agregás ventas o eliminás registros, el promedio real cambia y la consulta deja de representar la regla de negocio.

La versión correcta y dinámica usa una subquery:

SELECT *
FROM MOVIMIENTOS_FACTURADOS
WHERE IMPORTE > (
  SELECT AVG(IMPORTE)
  FROM MOVIMIENTOS_FACTURADOS
);

Cada vez que la ejecutás, SQL Server vuelve a calcular el promedio con los datos actuales. Por eso no tenés que editar el filtro manualmente.

Para repasar qué hacen AVG, MAX, MIN, SUM y COUNT, seguí con funciones de agregación en SQL Server.


Ejemplo 2: subquery con IN para obtener ventas delivery

Ahora la pregunta es distinta: queremos ver todas las ventas facturadas que también tienen un registro en MOVIMIENTOS_DELIVERY.

Primero, la consulta interna devuelve los IDs de movimientos que fueron delivery:

SELECT ID_MOVIMIENTO
FROM MOVIMIENTOS_DELIVERY;

Después usamos esa lista con IN en la tabla principal:

SELECT *
FROM MOVIMIENTOS_FACTURADOS
WHERE ID_MOVIMIENTO IN (
  SELECT ID_MOVIMIENTO
  FROM MOVIMIENTOS_DELIVERY
);

IN significa “está dentro de”. SQL Server toma los IDs devueltos por la subconsulta y conserva únicamente las filas de MOVIMIENTOS_FACTURADOS cuyos IDs estén en esa lista.

El resultado contiene la información de facturación de cada venta delivery: cliente, fecha, importe y medio de pago.

Contar cuántas ventas fueron delivery

Si en vez del detalle necesitás un total, reemplazá * por COUNT(*):

SELECT COUNT(*) AS CantidadVentasDelivery
FROM MOVIMIENTOS_FACTURADOS
WHERE ID_MOVIMIENTO IN (
  SELECT ID_MOVIMIENTO
  FROM MOVIMIENTOS_DELIVERY
);

Ejemplo 3: obtener la venta con mayor importe usando MAX

Esta consulta devuelve solamente el importe máximo:

SELECT MAX(IMPORTE) AS ImporteMaximo
FROM MOVIMIENTOS_FACTURADOS;

Es útil, pero no indica a qué cliente corresponde la venta ni muestra su fecha, medio de pago o ID. Para obtener la fila completa, comparamos todos los importes contra el valor máximo calculado por una subconsulta:

SELECT *
FROM MOVIMIENTOS_FACTURADOS
WHERE IMPORTE = (
  SELECT MAX(IMPORTE)
  FROM MOVIMIENTOS_FACTURADOS
);

La subconsulta obtiene el mayor IMPORTE; la consulta principal devuelve cada registro que coincide con él.


Resumen: cuándo usar cada subquery

NecesidadSubconsultaResultado
Ventas por encima de la mediaAVG(IMPORTE)Filtra usando un valor calculado dinámicamente.
Ventas que fueron deliveryID_MOVIMIENTO IN (...)Filtra usando una lista de IDs de otra tabla.
Datos de la venta más altaIMPORTE = (SELECT MAX(...))Devuelve la fila completa, no solo el máximo.

Las subqueries son especialmente útiles cuando una consulta necesita el resultado de otra para tomar una decisión. Empezá por estos tres patrones: una subconsulta que devuelve un valor (AVG o MAX) y una que devuelve varios valores para usar con IN.

Próximos pasos para practicar

  • Cambiá un importe y ejecutá otra vez la consulta con AVG para comprobar que el filtro se actualiza solo.
  • Probá MIN(IMPORTE) con la misma estructura para obtener la venta de menor importe.
  • Agregá un nuevo delivery y verificá cómo cambia el resultado de la consulta con IN.
  • Ejecutá un JOIN entre las dos tablas para mostrar también dirección, repartidor y estado del envío.

Mirá la explicación paso a paso en el video completo de subqueries en SQL Server.

En este artículo