LEFT JOIN
należy zastąpić OUTER APPLY
w następujących sytuacjach.
1. Jeśli chcemy połączyć dwa stoły na podstawie TOP n
wyniki
Zastanów się, czy musimy wybrać Id
i Name
od Master
i dwie ostatnie daty dla każdego Id
z Details
tabela.
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
co tworzy następujący wynik
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
Przyniesie to błędne wyniki, tj. przyniesie tylko ostatnie dwie daty z Details
tabela niezależnie od Id
mimo że łączymy się z Id
. Więc właściwym rozwiązaniem jest użycie 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
Oto działanie:W LEFT JOIN
, TOP 2
daty zostaną połączone z MASTER
dopiero po wykonaniu zapytania wewnątrz tabeli pochodnej D
. W OUTER APPLY
, używa łączenia WHERE M.ID=D.ID
wewnątrz OUTER APPLY
, aby każdy ID
w Master
zostanie połączony z TOP 2
daty, które przyniosą następujący wynik.
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. Kiedy potrzebujemy LEFT JOIN
funkcjonalność przy użyciu functions
.
OUTER APPLY
może być używany jako zamiennik LEFT JOIN
kiedy potrzebujemy uzyskać wynik z Master
tabela i function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
A funkcja jest tutaj.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE [email protected]
)
który wygenerował następujący wynik
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
3. Zachowaj NULL
wartości przy cofaniu obrotu
Weź pod uwagę, że masz poniższą tabelę
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
Gdy używasz UNPIVOT
przynieść FROMDATE
ORAZ TODATE
do jednej kolumny, wyeliminuje NULL
wartości domyślne.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
co generuje poniższy wynik. Zauważ, że przeoczyliśmy rekord Id
numer 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
W takich przypadkach APPLY
można użyć(albo CROSS APPLY
lub OUTER APPLY
, który jest wymienny).
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
który tworzy następujący wynik i zachowuje Id
gdzie jego wartość to 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