Contenido de esta guía
Qué problema resuelve LATERAL
Una subconsulta normal dentro de FROM se comporta como una tabla derivada independiente. LATERAL cambia esa relación: permite que la subconsulta use columnas de elementos anteriores del mismo FROM.
La idea mental es sencilla: toma una fila de la izquierda y ejecuta la subconsulta usando sus valores. Después combina el resultado con esa fila. Es especialmente útil cuando necesitas obtener una o varias filas relacionadas por cada elemento exterior, como el pedido más reciente de cada cliente o los dos productos más vendidos de cada categoría.
Sintaxis básica
SELECT ...
FROM tabla_exterior AS t
LEFT JOIN LATERAL (
SELECT ...
FROM tabla_relacionada AS r
WHERE r.clave = t.clave
ORDER BY ...
LIMIT 1
) AS x ON TRUE;La referencia a t.clave dentro de la subconsulta es lo importante: la tabla derivada depende de la fila exterior. Con LEFT JOIN LATERAL, una fila exterior puede conservarse aunque la subconsulta no encuentre coincidencias.
Ejemplo: último pedido de cada cliente
Queremos una fila por cliente con su pedido más reciente. Además, queremos conservar a los clientes que todavía no tienen pedidos.
SELECT c.id,
c.nombre,
ultimo.id AS pedido_id,
ultimo.fecha,
ultimo.total
FROM clientes AS c
LEFT JOIN LATERAL (
SELECT p.id, p.fecha, p.total
FROM pedidos AS p
WHERE p.cliente_id = c.id
ORDER BY p.fecha DESC, p.id DESC
LIMIT 1
) AS ultimo ON TRUE
ORDER BY c.id;| id | nombre | pedido_id | fecha | total |
|---|---|---|---|---|
| 1 | Ana Torres | 111 | 2025-06-01 | 249.0 |
| 2 | Luis Martín | 114 | 2025-06-08 | 203.9 |
| 3 | Marta Ruiz | 116 | 2025-06-12 | 999.0 |
| 4 | Diego López | 105 | 2025-05-15 | 69.9 |
| 5 | Sara Gómez | 115 | 2025-06-10 | 24.0 |
| 6 | Pablo Sanz | NULL | NULL | NULL |
La subconsulta ordena solo los pedidos del cliente que se está procesando y conserva el primero. El desempate por p.id DESC hace determinista la elección si dos pedidos comparten fecha. Pablo aparece con valores NULL porque LEFT JOIN LATERAL mantiene la fila exterior aunque no exista pedido.
El resultado se comprobó con el mismo conjunto educativo mediante una consulta equivalente con ROW_NUMBER() en el motor local.
CROSS JOIN LATERAL frente a LEFT JOIN LATERAL
CROSS JOIN LATERAL/JOIN LATERAL: si la subconsulta no devuelve filas, esa fila exterior desaparece del resultado.LEFT JOIN LATERAL: conserva la fila exterior y rellena conNULLlas columnas del resultado lateral cuando no hay coincidencia.
La elección se parece a la diferencia conceptual entre INNER JOIN y LEFT JOIN: decide si necesitas conservar filas sin relación.
SQL Server: CROSS APPLY y OUTER APPLY
SQL Server expresa este patrón con APPLY. CROSS APPLY elimina la fila izquierda cuando la parte derecha no devuelve nada; OUTER APPLY la conserva.
SELECT c.id,
c.nombre,
ultimo.id AS pedido_id,
ultimo.fecha,
ultimo.total
FROM clientes AS c
OUTER APPLY (
SELECT TOP (1) p.id, p.fecha, p.total
FROM pedidos AS p
WHERE p.cliente_id = c.id
ORDER BY p.fecha DESC, p.id DESC
) AS ultimo
ORDER BY c.id;No copies una sintaxis de un motor a otro de forma mecánica: la intención es equivalente, pero palabras clave y formas de limitar filas cambian.
Cuándo usar una alternativa
LATERAL no es la única manera de resolver «una fila relacionada por cada grupo». Una función de ventana con ROW_NUMBER() suele ser más portable y puede resultar más clara cuando quieres clasificar todo el conjunto antes de filtrar. Una subconsulta correlacionada escalar también puede servir si solo necesitas devolver un único valor.
No asumas que LATERAL es más rápido por definición. Los optimizadores pueden reescribir consultas y elegir planes distintos según índices, cardinalidades y distribución de datos. Para rendimiento, compara planes con EXPLAIN o la herramienta equivalente del motor real.
Olvidar que la subconsulta depende de cada fila exterior
Si la parte lateral devuelve muchas filas por cada cliente, el resultado puede crecer rápidamente. Antes de añadir LIMIT, filtros u ordenación, define cuántas filas necesitas realmente por elemento exterior.
Comprueba lo aprendido
Conserva clientes aunque no tengan pedidos
Escribe la consulta de PostgreSQL/MySQL que devuelva nombre, pedido_id y fecha del pedido más reciente de cada cliente. Los clientes sin pedidos también deben aparecer.
Criterio de éxito: usas una subconsulta lateral correlacionada con c.id, ordenas por fecha e id descendentes y eliges una sola fila.
LEFT JOIN.p.cliente_id = c.id.fecha DESC, después por id DESC y usa LIMIT 1.Solución razonada
SELECT c.nombre,
ultimo.id AS pedido_id,
ultimo.fecha
FROM clientes AS c
LEFT JOIN LATERAL (
SELECT p.id, p.fecha
FROM pedidos AS p
WHERE p.cliente_id = c.id
ORDER BY p.fecha DESC, p.id DESC
LIMIT 1
) AS ultimo ON TRUE
ORDER BY c.id;LEFT JOIN LATERAL conserva al cliente exterior. La subconsulta ve su id, busca únicamente sus pedidos y devuelve como máximo uno.
Qué debes recordar
LATERALpermite que una subconsulta deFROMuse columnas de elementos anteriores.LEFT JOIN LATERALconserva filas exteriores sin coincidencia.- SQL Server resuelve el mismo tipo de dependencia con
CROSS APPLYyOUTER APPLY. ROW_NUMBER()y subconsultas correlacionadas pueden ser alternativas más adecuadas según la intención.- El rendimiento depende del plan y de los datos; mídelo en el motor real.