Są różne sytuacje, w których nie można uniknąć CROSS APPLY
lub OUTER APPLY
.
Rozważ, że masz dwa stoły.
STÓŁ GŁÓWNY
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
TABELA SZCZEGÓŁÓW
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
ZASTOSUJ KRZYŻ
Istnieje wiele sytuacji, w której musimy wymienić INNER JOIN
z CROSS APPLY
.
1. Jeśli chcemy połączyć 2 tabele TOP n
wyników z INNER JOIN
funkcjonalnością
Rozważyć, czy musimy wybrać Id
i Name
od Master
a ostatnie dwa terminy dla każdego Id
z 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
Powyższe zapytanie generuje 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 |
x------x---------x--------------x-------x
Widzisz, wygenerował wyniki dla ostatnich dwóch dat z ostatnimi dwoma datami, Id
a następnie dołączył do tych rekordów tylko w zewnętrznym zapytaniu Id
, co jest błędne. Aby to osiągnąć, musimy użyć 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
i 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 | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
Oto praca. Zapytanie wewnątrz CROSS APPLY
może odwoływać się do zewnętrznej tabeli, gdzie INNER JOIN
nie może tego zrobić (zgłasza błąd kompilacji). Podczas wyszukiwania dwóch ostatnich dat, łączenie odbywa się wewnątrz CROSS APPLY
tj WHERE M.ID=D.ID
.
2. Kiedy potrzebujemy INNER JOIN
funkcjonalności za pomocą funkcji.
CROSS APPLY
może być używany jako zamiennik, INNER JOIN
gdy musimy uzyskać wynik z Master
tabeli i pliku function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
A oto funkcja
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
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 |
x------x---------x--------------x-------x
APLIKACJA ZEWNĘTRZNA
1. Jeśli chcemy połączyć 2 tabele TOP n
wyników z LEFT JOIN
funkcjonalnością
Zastanów się, czy musimy wybrać identyfikator i nazwę od Master
oraz ostatnie dwie daty dla każdego identyfikatora z Details
tabeli.
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
To przyniesie błędne wyniki, tzn. Przyniesie tylko ostatnie dwie daty z Details
tabeli, niezależnie od Id
tego, czy dołączymy do 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
co daje następujący pożądany rezultat
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ści przy użyciu functions
.
OUTER APPLY
może być używany jako zamiennik, LEFT JOIN
gdy musimy uzyskać wynik z Master
tabeli i pliku function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
I funkcja jest tutaj.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
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
Wspólna cecha CROSS APPLY
iOUTER APPLY
CROSS APPLY
lub OUTER APPLY
może służyć do zachowywania NULL
wartości podczas unieruchamiania, które są wymienne.
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
Jeśli użyjesz UNPIVOT
do przeniesienia FROMDATE
AND TODATE
do jednej kolumny, NULL
domyślnie wyeliminuje to wartości.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
co generuje poniższy wynik. Zauważ, że przegapiliśmy rekord Id
liczby3
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 CROSS APPLY
lub OUTER APPLY
będzie przydatna
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
który tworzy następujący wynik i zachowuje Id
tam, gdzie jest jego wartość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