Un LEFT JOIN
deve essere sostituito con OUTER APPLY
nelle seguenti situazioni.
TOP n
risultati
Considera se dobbiamo selezionare Id
e Name
da Master
e le ultime due date per ogni Id
da Details
tabella.
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
che forma il seguente risultato
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
Ciò porterà risultati errati, ovvero porterà solo i dati delle ultime due date da Details
tabella indipendentemente da Id
anche se ci uniamo con Id
. Quindi la soluzione corretta è usare 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
Ecco il funzionamento:In LEFT JOIN
, TOP 2
le date verranno unite al MASTER
solo dopo aver eseguito la query all'interno della tabella derivata D
. In OUTER APPLY
, usa l'unione di WHERE M.ID=D.ID
all'interno di OUTER APPLY
, in modo che ogni ID
in Master
sarà unito a TOP 2
date che porteranno il seguente risultato.
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
funzionalità utilizzando functions
.
OUTER APPLY
può essere utilizzato in sostituzione di LEFT JOIN
quando abbiamo bisogno di ottenere risultati da Master
tabella e una function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
E la funzione va qui.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE [email protected]
)
che ha generato il seguente risultato
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
valori quando non pivot
Considera di avere la tabella sottostante
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
Quando usi UNPIVOT
portare FROMDATE
E TODATE
su una colonna, eliminerà NULL
valori di default.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
che genera il risultato seguente. Nota che abbiamo perso il record di Id
numero 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
In questi casi un APPLY
può essere utilizzato (sia CROSS APPLY
o OUTER APPLY
, che è intercambiabile).
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
che forma il seguente risultato e conserva Id
dove il suo valore è 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