Hay varias situaciones en las que no puedes evitar CROSS APPLYo 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 JOINcon CROSS APPLY.
1. Si queremos unir 2 tablas de TOP nresultados con INNER JOINfuncionalidad
Considere si necesitamos seleccionar Idy Namedesde Mastery las dos últimas fechas para cada uno Idde 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 Idy 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 APPLYpuede hacer referencia a la tabla externa, donde INNER JOINno 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 JOINfuncionalidad usando funciones.
CROSS APPLYpuede usarse como un reemplazo INNER JOINcuando necesitamos obtener resultados de la Mastertabla 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 nresultados con LEFT JOINfuncionalidad
Considere si necesitamos seleccionar Id y Nombre de Mastery las dos últimas fechas para cada Id de la Detailstabla.
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 Detailstabla, independientemente de Idsi 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 JOINfuncionalidad usando functions.
OUTER APPLYpuede usarse como un reemplazo LEFT JOINcuando necesitamos obtener resultados de la Mastertabla 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 APPLYyOUTER APPLY
CROSS APPLYo OUTER APPLYse puede usar para retener NULLvalores 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 UNPIVOTpara llevar FROMDATEAND TODATEa una columna, eliminará los NULLvalores 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 Idnú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 APPLYo OUTER APPLYserá útil
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
que forma el siguiente resultado y retiene Iddonde 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