El operador APPLY (con sus variantes CROSS y OUTER) permite invocar una función con valores de tabla (TVF) o una subconsulta dinámica por cada fila devuelta por una tabla principal (la tabla de la izquierda).
Si acabas de dominar los JOINS, te sentirás invencible pudiendo conectar cualquier entidad. Pero tarde o temprano te toparás con un muro técnico: en un JOIN estándar, la parte derecha es “estática.
Imagina que tienes una Función de Tabla (TVF) que acepta un parámetro f(ClienteID) y devuelve los pedidos de ese cliente. Intentas hacer esto:
-- ⛔ ESTO DARÁ ERROR
SELECT ClientesNombre, F.PedidoID
FROM Clientes
INNER JOIN dbo.f_ObtenerPedidos(Clientes.ClienteID) F ON ...
SQL Server se va quejar. ¿Por qué? Porque en un JOIN estándar, la parte derecha es “estática”. No puede ver ni usar los valores de la fila actual de la izquierda (C.ClienteID) para calcularse a sí misma.
Para solucionar esto (y hacer cosas mucho más interesantes), Microsoft introdujo el operador APPLY.
No es una herramienta que quizás no uses todos los días, pero el día que la necesites, te salvará la papeleta.
¿Qué es APPLY?
Piensa en APPLY como un bucle FOREACH optimizado para SQL.
Toma una fila de la tabla de la izquierda (Tabla A).
“Inyecta” los valores de esa fila en la expresión de la derecha (Tabla B, Función o Subconsulta).
Calcula el resultado para esa fila específica.
Une los resultados y pasa a la siguiente fila.
Esto permite lo que llamamos Correlación: la consulta de la derecha depende de la fila de la izquierda.
Los dos sabores: CROSS vs OUTER
La distinción es idéntica a la que existe entre INNER JOIN y LEFT JOIN.
Equivale a un INNER JOIN.
- Ejecuta la lógica derecha para cada fila de la izquierda.
- Si la parte derecha no devuelve resultados, la fila de la izquierda desaparece.
Equivale a un LEFT JOIN.
- Ejecuta la lógica derecha.
- Si la parte derecha no devuelve resultados, se mantiene la fila de la izquierda y se rellenan las columnas derechas con NULL.
Unir con Funciones de Tabla (TVF)
Este fue el motivo original por el que se creó este operador. Si tienes una función que requiere parámetros de la tabla principal, tienes que usar APPLY.
SELECT
C.Nombre,
P.Producto,
P.Total
FROM Clientes C
OUTER APPLY dbo.ufn_ObtenerUltimos3Pedidos(C.ClienteID) P;
Aquí, por cada cliente, SQL ejecuta la función pasándole su ID.
- Si usáramos
CROSS APPLY: Los clientes sin pedidos no saldrían en el reporte. - Al usar
OUTER APPLY: Los clientes sin pedidos salen conNULLen Producto y Total.
