Ci sono varie situazioni in cui non è possibile evitare CROSS APPLY
o OUTER APPLY
.
Considerate che avete due tabelle.
MASTER TABELLA
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
DATI TABELLA
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
CROSS APPLICA
ci sono molte situazioni in cui abbiamo bisogno di sostituire INNER JOIN
con CROSS APPLY
.
1. Se vogliamo unire 2 tabelle su TOP n
risultati con INNER JOIN
funzionalità
considerare se dobbiamo selezionare Id
e Name
da Master
e le ultime due date per ogni Id
da 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 query sopra riportata genera 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 |
x------x---------x--------------x-------x
Sede, ha generato risultati per due date con due ultime data Id
e poi si è unito questi record solo in query esterna su Id
, che è sbagliato. Per fare ciò, dobbiamo usare 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
e forme che segue 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 |
x------x---------x--------------x-------x
Ecco il funzionamento. La query all'interno di CROSS APPLY
può fare riferimento alla tabella esterna, dove INNER JOIN
non può eseguire questa operazione (genera errore di compilazione). Quando si trovano le ultime due date, l'unione viene eseguita all'interno di CROSS APPLY
ie, WHERE M.ID=D.ID
.
2. Quando è necessaria la funzionalità INNER JOIN
tramite le funzioni.
CROSS APPLY
può essere usato come una sostituzione con INNER JOIN
quando abbiamo bisogno di ottenere il risultato di Master
tavolo e un function
.
Ed ecco la funzione
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 |
x------x---------x--------------x-------x
ESTERNO APPLICABILE
1. Se vogliamo unire 2 tabelle su TOP n
risultati con LEFT JOIN
funzionalità
Considerare se è necessario selezionare Id e Nome da Master
e le ultime due date per ogni Id dalla tabella Details
.
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
Questo porterà risultati errati esempio, che porterà solo i dati più recenti due date da Details
tabella indipendentemente Id
anche se ci uniamo con Id
. Quindi la soluzione corretta sta usando 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
che forma il seguente risultato desiderato
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. Quando occorre LEFT JOIN
funzionalità utilizzando functions
.
OUTER APPLY
può essere usato come una sostituzione con LEFT JOIN
quando abbiamo bisogno di ottenere il risultato di Master
tavolo e un 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
caratteristica comune delle CROSS APPLY
e OUTER APPLY
CROSS APPLY
o OUTER APPLY
possono essere utilizzati per mantenere NULL
valori quando unpivoting, intercambiabili.
considera di avere una 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 si utilizza UNPIVOT
di portare FROMDATE
E TODATE
a una colonna, si occuperà di eliminare NULL
valori di default.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
che genera il risultato di seguito.Si noti 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 CROSS APPLY
o OUTER APPLY
sarà utile
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
che forma il seguente risultato e mantiene Id
quando 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
"top n per gruppo" o analisi XML è comune. Vedi alcune delle mie risposte http://stackoverflow.com/search?tab=votes&q=user%3a27535%20%22cross%20apply%22%20or%20%22outer%20apply%22 – gbn
http://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/ – mehrdad
http://explainextended.com/2009/07/16/inner-join-vs-cross-apply/ –