Ci sono varie situazioni in cui non puoi evitare CROSS APPLYo OUTER APPLY.
Considera di avere due tavoli.
TABELLA MASTER
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
TABELLA DETTAGLI
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
APPLICAZIONE CROCE
Ci sono molte situazioni in cui abbiamo bisogno di sostituire INNER JOINcon CROSS APPLY.
1. Se vogliamo unire 2 tabelle sui TOP nrisultati con INNER JOINfunzionalità
Considera se dobbiamo selezionare Ide Nameda Mastere ultime due date per ognuna Idda 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 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
Vedi, ha generato risultati per le ultime due date con le ultime due date Ide poi ha unito questi record solo nella query esterna attiva Id, il 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 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 | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
Ecco il lavoro. La query interna CROSS APPLYpuò fare riferimento alla tabella esterna, dove INNER JOINnon è possibile farlo (genera errore di compilazione). Quando si trovano le ultime due date, l'unione avviene all'interno CROSS APPLY, ad es WHERE M.ID=D.ID.
2. Quando abbiamo bisogno di INNER JOINfunzionalità usando le funzioni.
CROSS APPLYpuò essere usato in sostituzione di INNER JOINquando abbiamo bisogno di ottenere risultati dalla Mastertabella e a function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Ed ecco la funzione
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
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
APPLICARE ESTERNO
1. Se vogliamo unire 2 tabelle sui TOP nrisultati con LEFT JOINfunzionalità
Considera se dobbiamo selezionare Id e Nome da Mastere le ultime due date per ogni ID dalla Detailstabella.
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 costituisce 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à a risultati errati, cioè porterà solo i dati delle ultime due date dalla Detailstabella, indipendentemente dal fatto che Idci uniamo Id. Quindi sta usando la soluzione corretta 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 costituisce 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 abbiamo bisogno di LEFT JOINfunzionalità utilizzando functions.
OUTER APPLYpuò essere usato in sostituzione di LEFT JOINquando abbiamo bisogno di ottenere risultati dalla Mastertabella e a 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 ID=@Id
)
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 di CROSS APPLYeOUTER APPLY
CROSS APPLYo OUTER APPLYpuò essere usato per conservare NULLvalori quando non si fa perno, che sono intercambiabili.
Considera di avere la tabella seguente
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 UNPIVOTper portare FROMDATEAND TODATEin una colonna, eliminerà i NULLvalori per impostazione predefinita.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
che genera il risultato seguente. Si noti che abbiamo perso il record del Idnumero3
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 tali casi un CROSS APPLYo OUTER APPLYsarà utile
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
che forma il seguente risultato e conserva Iddove si trova il suo valore3
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