Hay varias situaciones en las que no puedes evitar CROSS APPLY
o OUTER APPLY
.
Considera que tienes dos mesas.
MESA PRINCIPAL
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
TABLA DE DETALLES
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
APLICACIÓN CRUZADA
Hay muchas situaciones donde tenemos que reemplazar INNER JOIN
con CROSS APPLY
.
1. Si queremos unir 2 tablas de TOP n
resultados con INNER JOIN
funcionalidad
Considere si necesitamos seleccionar Id
y Name
desde Master
y las dos últimas fechas para cada uno Id
de Details table
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
La consulta anterior genera el siguiente resultado.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
x------x---------x--------------x-------x
Vea, generó resultados para las últimas dos fechas con las últimas dos fechas Id
y luego unió estos registros solo en la consulta externa Id
, lo cual es incorrecto. Para lograr esto, necesitamos usar CROSS APPLY
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
y forma el siguiente resultado.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
Aquí está el trabajo. La consulta dentro CROSS APPLY
puede hacer referencia a la tabla externa, donde INNER JOIN
no puede hacer esto (arroja un error de compilación). Cuando la búsqueda de las dos últimas fechas, uniéndose a que se hace en el interior CROSS APPLY
, es decir, WHERE M.ID=D.ID
.
2. Cuando necesitamos INNER JOIN
funcionalidad usando funciones.
CROSS APPLY
puede usarse como un reemplazo INNER JOIN
cuando necesitamos obtener resultados de la Master
tabla y a function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Y aquí está la función.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
que generó el siguiente resultado
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
x------x---------x--------------x-------x
APLICACIÓN EXTERIOR
1. Si queremos unir 2 tablas de TOP n
resultados con LEFT JOIN
funcionalidad
Considere si necesitamos seleccionar Id y Nombre de Master
y las dos últimas fechas para cada Id de la Details
tabla.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
LEFT JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
que forma el siguiente resultado
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | NULL | NULL |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
Esto traerá resultados incorrectos, es decir, traerá solo los últimos datos de dos fechas de la Details
tabla, independientemente de Id
si nos unimos Id
. Entonces, la solución adecuada es usar OUTER APPLY
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
OUTER APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
que forma el siguiente resultado deseado
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
2. Cuando necesitamos LEFT JOIN
funcionalidad usando functions
.
OUTER APPLY
puede usarse como un reemplazo LEFT JOIN
cuando necesitamos obtener resultados de la Master
tabla y a function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Y la función va aquí.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
que generó el siguiente resultado
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
Característica común de CROSS APPLY
yOUTER APPLY
CROSS APPLY
o OUTER APPLY
se puede usar para retener NULL
valores al desconectar, que son intercambiables.
Considera que tienes la tabla de abajo
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
Cuando usa UNPIVOT
para llevar FROMDATE
AND TODATE
a una columna, eliminará los NULL
valores por defecto.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
que genera el siguiente resultado. Tenga en cuenta que hemos perdido el registro de Id
número3
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
x------x-------------x
En tales casos, un CROSS APPLY
o OUTER APPLY
será útil
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
que forma el siguiente resultado y retiene Id
donde está su valor3
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
| 3 | NULL |
x------x-------------x