Es gibt verschiedene Situationen , in denen man nicht vermeiden kann CROSS APPLYoder OUTER APPLY.
Angenommen, Sie haben zwei Tabellen.
MASTER TABLE
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
DETAILS TABELLE
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 APPLY
Es gibt viele Situation , wo wir ersetzen müssen INNER JOINmitCROSS APPLY .
1. Wenn wir 2 Tabellen zu TOP nErgebnissen mit verbinden möchtenINNER JOIN Funktionalität
Überlegen Sie, ob wir müssen wählen Idund Nameaus Masterund die letzten beiden Tage , für jeden Idaus 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
Die obige Abfrage generiert das folgende Ergebnis.
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
Es wurden Ergebnisse für die letzten beiden Daten mit den letzten beiden Daten generiert Idund diese Datensätze dann nur in der äußeren Abfrage am verknüpft Id, was falsch ist. Um dies zu erreichen, müssen wir verwenden 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
und bildet er folgendes Ergebnis.
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
Hier ist die Arbeit. Die Abfrage im Inneren CROSS APPLYkann auf die äußere Tabelle verweisen, wo INNER JOINdies nicht möglich ist (löst einen Kompilierungsfehler aus). Wenn Sie die letzten beiden Daten gefunden haben, erfolgt der Beitritt innerhalb von, CROSS APPLYdhWHERE M.ID=D.ID .
2. Wenn wir INNER JOINFunktionalität mit Funktionen benötigen .
CROSS APPLYkann als Ersatz verwendet werden, INNER JOINwenn wir Ergebnisse aus MasterTabelle und a erhalten müssen function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Und hier ist die Funktion
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
welches das folgende Ergebnis erzeugte
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
AUSSEN ANWENDEN
1. Wenn wir 2 Tabellen zu TOP nErgebnissen mit verbinden möchtenLEFT JOIN Funktionalität
Überlegen Sie, ob wir ID und Name aus Masterund die letzten beiden Daten für jede ID aus der DetailsTabelle auswählen müssen .
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
welches das folgende Ergebnis bildet
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
Dies führt zu falschen Ergebnissen, dh es werden nur die Daten der letzten beiden Daten aus der DetailsTabelle angezeigt, unabhängig davon Id, ob wir uns anschließen oder nicht Id. Die richtige Lösung ist also 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
welches das folgende gewünschte Ergebnis bildet
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. Wenn wir LEFT JOINFunktionalität mit benötigen functions.
OUTER APPLYkann als Ersatz verwendet werden, LEFT JOINwenn wir Ergebnisse aus MasterTabelle und a erhalten müssen function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Und die Funktion geht hier.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
welches das folgende Ergebnis erzeugte
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
Gemeinsames Merkmal von CROSS APPLYundOUTER APPLY
CROSS APPLYoder OUTER APPLYkann verwendet werden, um NULLbeim Schwenken Werte beizubehalten, die austauschbar sind.
Angenommen, Sie haben die folgende Tabelle
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
Wenn Sie UNPIVOTbringen FROMDATEund TODATEzu einer Spalte, wird es beseitigen NULLWerte standardmäßig.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
Dies erzeugt das folgende Ergebnis. Beachten Sie, dass wir den Datensatz der IdNummer verpasst haben3
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 solchen Fällen ist ein CROSS APPLYoder OUTER APPLYnützlich
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
Dies bildet das folgende Ergebnis und behält bei, Idwo sein Wert ist3
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