Cómo aplicar alias en subconsultas SQL para mejorar la legibilidad

Imagen educativa sobre alias en subconsultas SQL. Muestra código con una subconsulta que agrupa clientes por ciudad y la consulta externa que usa alias cl y agg para obtener nombre y total_clientes de manera clara y legible.

Cuando empezás a escribir SQL, casi todo se resuelve con SELECT … FROM … WHERE …. Pero muy pronto aparecen las subconsultas: consultas dentro de otra consulta. Son poderosas… y si no las escribís con alias claros, se vuelven difíciles de leer, de depurar y de mantener.

En esta guía vas a aprender, desde cero y paso a paso, cómo usar alias en subconsultas para que tu SQL sea claro, profesional y fácil de entender. Veremos subconsultas en FROM, en WHERE con IN/EXISTS, subconsultas escalares en la lista SELECT, la relación con CTE (WITH) y un set de buenas prácticas de nombres. Incluyo tablas de resultados simplificadas para que se entienda qué devuelve cada ejemplo.

1) ¿Qué es una subconsulta? (y por qué los alias importan)

Una subconsulta es una consulta anidada dentro de otra. Puede aparecer en varias partes:

  • En FROM (también llamada tabla derivada o inline view).
  • En WHERE (muy común con IN o EXISTS).
  • En la lista SELECT (subconsulta escalar: devuelve un solo valor por fila).

¿Por qué usar alias?
Porque una subconsulta, especialmente en FROM, se comporta como una tabla. Igual que cualquier tabla, necesita un nombre para referirse a sus columnas desde afuera. Además, los alias:

  • Aclaran qué hace cada bloque (ej.: ventas_30d, agg, top_por_categoria).
  • Evitan ambigüedad cuando hay varias tablas con columnas homónimas (id, fecha, total).
  • Ayudan a dividir el problema en piezas que se entienden de un vistazo.

2) Subconsulta en FROM: alias obligatorio

Imaginá dos tablas:

  • clientes(id, nombre)
  • pedidos(id, cliente_id, fecha, total)

Queremos el total de ventas por cliente en los últimos 30 días. Una forma clásica es calcular primero un agregado por cliente en una subconsulta y ponerle un alias.

2.1 Versión correcta (con alias de subconsulta y alias de columnas)

SELECT
  c.nombre              AS cliente,
  agg.pedidos           AS cantidad_pedidos,
  agg.ventas            AS ventas_30d
FROM clientes AS c
JOIN (
  SELECT
    p.cliente_id,
    COUNT(*)            AS pedidos,
    SUM(p.total)        AS ventas
  FROM pedidos AS p
  WHERE p.fecha >= CURRENT_DATE - INTERVAL '30 days'
  GROUP BY p.cliente_id
) AS agg
  ON agg.cliente_id = c.id
ORDER BY agg.ventas DESC;
  • La subconsulta recibe el alias agg (de aggregate).
  • Dentro, las columnas tienen alias semánticos: pedidos, ventas.
  • Afuera, usamos esos nombres para producir una salida entendible.

Resultado (simplificado):

clientecantidad_pedidosventas_30d
Elsa4900.00
Carla2720.00
Ana2440.00

2.2 ¿Qué pasa si no le ponés alias?

SELECT c.nombre, t.ventas
FROM clientes c
JOIN (SELECT cliente_id, SUM(total) AS ventas FROM pedidos GROUP BY cliente_id)  -- ❌ falta alias aquí
  ON t.cliente_id = c.id;

Falla. Las bases exigen alias cuando hay una subconsulta en FROM. El parser necesita un nombre para ese bloque.

3) Alias dentro de la subconsulta vs fuera de la subconsulta

  • Dentro de la subconsulta: alias para tablas internas (p) y para columnas calculadas (ventas, pedidos).
  • Fuera de la subconsulta: alias del “bloque” completo (agg) para poder referenciar sus columnas (agg.ventas).

Esto hace que cada capa sea autoexplicativa. Un buen patrón de nombres:

  • base para datos sin procesar,
  • agg para agregaciones,
  • top_… para rankings,
  • resumen_…, ventas_30d, por_ciudad, etc.

4) Subconsulta en WHERE con IN: alias que ordenan la lógica

Supongamos que queremos todos los clientes que compraron algo caro (por ejemplo, pedidos con total > 300). Podemos filtrar por id usando una subconsulta con IN.

SELECT
  c.id     AS cliente_id,
  c.nombre AS cliente
FROM clientes AS c
WHERE c.id IN (
  SELECT p.cliente_id
  FROM pedidos AS p
  WHERE p.total > 300
);
  • El alias p organiza la subconsulta y la hace legible.
  • El resultado lista clientes que cumplieron esa condición al menos una vez.

Resultado (ejemplo):

cliente_idcliente
3Carla
5Elsa

Nota: la subconsulta en WHERE no requiere un alias para todo el bloque (como en FROM), pero sí conviene usar alias para las tablas dentro de esa subconsulta.

5) Subconsulta correlacionada con EXISTS: alias para entender el “diálogo” entre consultas

EXISTS verifica si la subconsulta devuelve al menos una fila. Lo común es que la subconsulta use la fila actual de la consulta externa (esto se llama correlación).

SELECT
  c.id,
  c.nombre
FROM clientes AS c
WHERE EXISTS (
  SELECT 1
  FROM pedidos AS p
  WHERE p.cliente_id = c.id         -- ← correlación
    AND p.fecha >= CURRENT_DATE - INTERVAL '30 days'
);
  • c (afuera) y p (adentro) hacen visible la correlación p.cliente_id = c.id.
  • Con alias, se lee como una frase: “clientes c para los que existen pedidos p en los últimos 30 días”.

¿Cuándo usar EXISTS vs IN?

  • IN es simple cuando comparás una sola columna y no hay duplicados problemáticos.
  • EXISTS suele ser más claro (y a veces más eficiente) cuando la lógica depende de múltiples condiciones o uniones dentro de la subconsulta.

6) Subconsultas escalares en la lista SELECT (un valor por fila)

Una subconsulta escalar es la que devuelve un único valor para cada fila externa. Por ejemplo, queremos, para cada cliente, la fecha de su último pedido:

SELECT
  c.id      AS cliente_id,
  c.nombre  AS cliente,
  (
    SELECT MAX(p.fecha)
    FROM pedidos AS p
    WHERE p.cliente_id = c.id
  ) AS ultima_compra
FROM clientes AS c
ORDER BY ultima_compra DESC NULLS LAST;
  • El alias ultima_compra explica el significado del valor.
  • Si un cliente no tiene pedidos, el valor será NULL.

Resultado (ejemplo):

cliente_idclienteultima_compra
5Elsa2024-06-20
3Carla2024-06-12
8Hugo(NULL)

Diferencia con JOIN: una subconsulta escalar no duplica filas de la tabla externa; en cambio, trae un solo dato calculado para cada fila.

7) De subconsulta a CTE (WITH): ¿cuándo conviene?

A veces la subconsulta de FROM crece y crece. Para que el SQL sea más fácil de leer y reutilizar, conviene subirla a un CTE (expresión común de tabla).

7.1 Con subconsulta en FROM

SELECT c.nombre, agg.ventas
FROM clientes c
JOIN (
  SELECT cliente_id, SUM(total) AS ventas
  FROM pedidos
  WHERE fecha >= CURRENT_DATE - INTERVAL '30 days'
  GROUP BY cliente_id
) AS agg ON agg.cliente_id = c.id
ORDER BY agg.ventas DESC;

7.2 La misma lógica con CTE (más legible)

WITH ventas_30d AS (
  SELECT cliente_id, SUM(total) AS ventas
  FROM pedidos
  WHERE fecha >= CURRENT_DATE - INTERVAL '30 days'
  GROUP BY cliente_id
)
SELECT
  c.nombre AS cliente,
  v.ventas AS ventas_30d
FROM clientes AS c
JOIN ventas_30d AS v ON v.cliente_id = c.id
ORDER BY v.ventas DESC;
  • El alias del CTE es el nombre del bloque (ventas_30d).
  • Luego se usa como si fuera una tabla (v), con sus alias de columnas (ventas).

Cuándo usar CTE:

  • La subconsulta se usa más de una vez.
  • La consulta necesita etapas (base → agregado → ranking).
  • Quieres comentar, testear o leer cada pieza por separado.

8) Buenas prácticas de alias específicas para subconsultas

  • Nombres que cuentan una historia: ventas_30d, agg_clientes, top_por_categoria, resumen_mensual.
  • Evitar t1, sub, tmp salvo en demos mínimos.
  • Prefijos por propósito:
    • agg_ (agregaciones), dim_ (dimensiones), fact_ (hechos), rnk_ (rankings).
  • Alias cortos para tablas internas: c (clientes), p (pedidos), e (empleados).
  • Alias de columnas semánticos: ventas, pedidos, ticket_promedio, ultima_compra.
  • Consistencia de estilo: snake_case en minúsculas (ventas_ciudad), sin acentos y evitando palabras reservadas.

9) Errores comunes (y cómo corregirlos)

  1. Olvidar el alias de la subconsulta en FROM
    • Síntoma: error de sintaxis.
    • Solución: … FROM (subconsulta) AS nombre_bloque.
  2. Alias duplicados o confusos
    • Síntoma: columnas o bloques que se pisan o no se entiende de dónde vienen.
    • Solución: alias únicos y descriptivos.
  3. Usar alias de SELECT en WHERE
    • Motivo: orden lógico; WHERE se evalúa antes que SELECT.
    • Solución: repetí la expresión o subila a subconsulta/CTE.
  4. Ambigüedad de columna (mismo nombre en varias tablas)
    • Síntoma: “column reference is ambiguous”.
    • Solución: calificar con alias de tabla: c.id, p.id.
  5. Subconsultas escalares que devuelven >1 fila
    • Síntoma: error “more than one row returned”.
    • Solución: agregá MAX, MIN, LIMIT 1/TOP 1/FETCH FIRST 1 ROW ONLY según motor.
  6. Rendimiento (subconsultas correlacionadas pesadas)
    • Solución: mover a CTE o a JOIN + agregación si corresponde, y crear índices adecuados (cliente_id, fecha).

10) Tres casos completos con subconsultas + alias

10.1 “Clientes activos con gasto y última compra” (subconsulta en FROM + escalar)

SELECT
  c.id                           AS cliente_id,
  c.nombre                       AS cliente,
  agg.ventas                     AS ventas_30d,
  (
    SELECT MAX(p.fecha)
    FROM pedidos AS p
    WHERE p.cliente_id = c.id
  )                              AS ultima_compra
FROM clientes AS c
JOIN (
  SELECT
    p.cliente_id,
    SUM(p.total) AS ventas
  FROM pedidos AS p
  WHERE p.fecha >= CURRENT_DATE - INTERVAL '30 days'
  GROUP BY p.cliente_id
) AS agg ON agg.cliente_id = c.id
WHERE c.activo = TRUE
ORDER BY agg.ventas DESC;

Salida (ejemplo):

cliente_idclienteventas_30dultima_compra
5Elsa900.002024-06-20
3Carla720.002024-06-12

10.2 “Top 3 productos por categoría” (subconsulta correlacionada)

Tablas: productos(id, nombre, categoria, precio) y ventas(id, producto_id, unidades).

SELECT
  pr.categoria,
  pr.nombre      AS producto,
  SUM(v.unidades) AS unidades
FROM productos AS pr
JOIN ventas    AS v ON v.producto_id = pr.id
GROUP BY pr.categoria, pr.nombre
HAVING
  SUM(v.unidades) >= (
    SELECT
      MIN(t3.unidades)
    FROM (
      SELECT
        p2.nombre,
        SUM(v2.unidades) AS unidades
      FROM productos p2
      JOIN ventas    v2 ON v2.producto_id = p2.id
      WHERE p2.categoria = pr.categoria          -- ← correlación por categoría
      GROUP BY p2.nombre
      ORDER BY unidades DESC
      FETCH FIRST 3 ROWS ONLY                     -- TOP 3 por categoría (PostgreSQL/Oracle). En MySQL usar LIMIT 3.
    ) AS t3
  )
ORDER BY pr.categoria, unidades DESC;
  • t3 es una subconsulta que calcula las top 3 unidades por categoría; usamos su mínimo para filtrar los que entran.
  • Alias claros explican cada nivel (t3, p2, v2).

10.3 “Último pedido por cliente con detalle” (subconsulta + join para traer columnas auxiliares)

-- Subconsulta: por cliente, su última fecha de pedido
SELECT
  c.nombre AS cliente,
  p2.fecha AS fecha_ultima,
  p2.total AS total_ultimo
FROM clientes AS c
JOIN (
  SELECT p.cliente_id, MAX(p.fecha) AS fecha_ultima
  FROM pedidos AS p
  GROUP BY p.cliente_id
) AS ult ON ult.cliente_id = c.id
JOIN pedidos AS p2
  ON p2.cliente_id = c.id
 AND p2.fecha      = ult.fecha_ultima
ORDER BY p2.fecha DESC;
  • ult obtiene la última fecha por cliente.
  • Luego unimos con pedidos p2 para traer total, id del pedido, etc.

Resultado (ejemplo):

clientefecha_ultimatotal_ultimo
Elsa2024-06-20320.00
Carla2024-06-12220.00

11) Diferencias entre motores (para escribir subconsultas portables)

  • Límites:
    • PostgreSQL / Oracle: FETCH FIRST 1 ROW ONLY o LIMIT 1 (PostgreSQL).
    • MySQL / MariaDB: LIMIT 1.
    • SQL Server: TOP 1 al principio del SELECT.
  • Fechas:
    • PostgreSQL/Oracle: CURRENT_DATE - INTERVAL '30 days'.
    • MySQL: CURDATE() - INTERVAL 30 DAY.
    • SQL Server: DATEADD(DAY, -30, CAST(GETDATE() AS DATE)).
  • Comillas para alias con espacios:
    • Estándar/PG/Oracle: "Nombre completo".
    • SQL Server: [Nombre completo] o "Nombre completo".
    • MySQL: "Nombre completo" (según sql_mode) o `Nombre completo`.

Sugerencia universal:

  • Evitá espacios y acentos en alias; preferí snake_case.
  • Usá AS (aunque sea opcional) por claridad.
  • Elegí alias semánticos (de negocio).

12) Checklist rápido antes de publicar/compartir tu consulta

  • ¿Cada subconsulta en FROM tiene alias (ej.: agg, ventas_30d)?
  • ¿Las tablas internas dentro de la subconsulta tienen alias cortos (c, p)?
  • ¿Las columnas calculadas tienen nombres de negocio (ventas, pedidos, ultima_compra)?
  • ¿Evitaste palabras reservadas y alias duplicados?
  • ¿Tu subconsulta escalar garantiza devolver una sola fila por cada fila externa?
  • ¿Consideraste mover subconsultas grandes a CTE para legibilidad/reutilización?

Cierre

Las subconsultas permiten resolver problemas complejos con SQL sin perder claridad, siempre que les des alias correctos. Pensá cada subconsulta como una pieza con nombre y propósito: “esta calcula ventas_30d”, “esta trae el top por categoría”, “esta obtiene la última compra”. Con alias descriptivos y consistentes, tu SQL se vuelve legible, mantenible y apto para colaborar en equipo —sin sustos cuando vuelvas al código dentro de seis meses.

📚 Artículos relacionados

Scroll al inicio