Są różne sytuacje, w których nie można uniknąć CROSS APPLYlub 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 JOINz CROSS APPLY.
1. Jeśli chcemy połączyć 2 tabele TOP nwyników z INNER JOINfunkcjonalnością
Rozważyć, czy musimy wybrać Idi Nameod Mastera ostatnie dwa terminy dla każdego Idz 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, Ida 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 APPLYmoże odwoływać się do zewnętrznej tabeli, gdzie INNER JOINnie może tego zrobić (zgłasza błąd kompilacji). Podczas wyszukiwania dwóch ostatnich dat, łączenie odbywa się wewnątrz CROSS APPLYtj WHERE M.ID=D.ID.
2. Kiedy potrzebujemy INNER JOINfunkcjonalności za pomocą funkcji.
CROSS APPLYmoże być używany jako zamiennik, INNER JOINgdy musimy uzyskać wynik z Mastertabeli 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 nwyników z LEFT JOINfunkcjonalnością
Zastanów się, czy musimy wybrać identyfikator i nazwę od Masteroraz ostatnie dwie daty dla każdego identyfikatora z Detailstabeli.
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 Detailstabeli, niezależnie od Idtego, 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 JOINfunkcjonalności przy użyciu functions.
OUTER APPLYmoże być używany jako zamiennik, LEFT JOINgdy musimy uzyskać wynik z Mastertabeli 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 APPLYiOUTER APPLY
CROSS APPLYlub OUTER APPLYmoże służyć do zachowywania NULLwartoś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 UNPIVOTdo przeniesienia FROMDATEAND TODATEdo jednej kolumny, NULLdomyś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 Idliczby3
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 APPLYlub OUTER APPLYbędzie przydatna
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
który tworzy następujący wynik i zachowuje Idtam, 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