A LEFT JOIN
debe reemplazarse con OUTER APPLY
en las siguientes situaciones.
TOP n
resultados
Considere si necesitamos seleccionar Id
y Name
de Master
y las dos últimas fechas para cada Id
de Details
mesa.
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 datos de las dos últimas fechas de Details
tabla independientemente de Id
aunque nos unimos con 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
Aquí está el funcionamiento:En LEFT JOIN
, TOP 2
las fechas se unirán al MASTER
solo después de ejecutar la consulta dentro de la tabla derivada D
. En OUTER APPLY
, utiliza la unión WHERE M.ID=D.ID
dentro de la OUTER APPLY
, para que cada ID
en Master
se unirá con TOP 2
fechas que traerán 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 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
LEFT JOIN
funcionalidad usando functions
.
OUTER APPLY
se puede usar como reemplazo de LEFT JOIN
cuando necesitamos obtener el resultado de Master
tabla y una 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 [email protected]
)
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
NULL
valores al des-pivotar
Considere que tiene la siguiente tabla
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 usas UNPIVOT
traer FROMDATE
Y TODATE
a una columna, eliminará NULL
valores por defecto.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
lo que genera el siguiente resultado. Tenga en cuenta que hemos perdido el registro de Id
número 3
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 APPLY
se puede usar (ya sea CROSS APPLY
o OUTER APPLY
, que es intercambiable).
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
que forma el siguiente resultado y retiene Id
donde su valor es 3
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