Der APPLY Operator wurde mit dem SQL Server 2005 eingeführt und ist seitdem Bestandteil des Transact-SQL Sprachumfangs.
Er erlaubt die Zeilen einer Tabelle mit einer Tabellenwertfunktion oder einem Tabellenausdruck zu verbinden.
Die Funktionsweise des APPLY Operators lässt sich am einfachsten an einigen Beispielen erläutern.
Eine Aufgabenstellung könnte wie folgt lauten:
Aus einer Tabelle mit ausreichend Umsatz-Datensätzen sollen für die Top 5 Kunden die Top 5 Produkte ermittelt werden.
Durch das Schlüsselwort „jeweils“ könnte die Aufgabe noch präziser formuliert werden.
Für die Top 5 Kunden sollen jeweils die Top 5 Produkte ermittelt werden.
Diese Formulierung macht bereits deutlich, wie bei der Lösung der Aufgabe vorzugehen ist.
Für die Beispiele verwenden wir die Chair-Datenbank unseres fiktiven Stühleherstellers.
Die Top 5 Kunden zu ermitteln ist relativ einfach.
SELECT TOP 5 KundeID, SUM(Umsatz) Gesamtumsatz
FROM T_FACT_01_Deckungsbeitragsrechnung
GROUP BY KundeID
ORDER BY SUM(Umsatz) DESC
Die Syntax zur Ermittlung der Top 5 Produkte würde analog lauten.
Die Top 5 Kunden und die Top 5 Produkte allein bringen uns aber nicht zur Lösung. Wie in der Aufgabenstellung formuliert, müssen für jeden Kunden (aus dem obigen SQL-Statement) dessen Top fünf Produkte gefunden werden.
Zu diesem Zweck erstellen wir eine SQL-Funktion, der wir einen Kunden übergeben können und welche uns die Top Produkte dieses Kunden zurückliefert.
CREATE FUNCTION getTop5ProductsForCustomer (@CustomerID varchar(50)) RETURNS table AS
RETURN
(
SELECT TOP 5 ProduktID, SUM(Umsatz) Gesamtumsatz
FROM dbo.T_FACT_01_Deckungsbeitragsrechnung
WHERE KundeID = @CustomerID
GROUP BY ProduktID
ORDER BY SUM(Umsatz) DESC
);
GO
Mit Hilfe des CROSS APPLY Statements wird die eben gebaute Funktion für jeden der Top fünf Kunden ausgeführt.
SELECT t.KundeID
,f.ProduktID
,f.Gesamtumsatz
FROM (
SELECT TOP 5 KundeID, SUM(Umsatz) K_Umsatz
FROM dbo.T_FACT_01_Deckungsbeitragsrechnung
GROUP BY KundeID
ORDER BY SUM(Umsatz) DESC
) AS t
CROSS APPLY dbo.getTop5ProductsForCustomer(t.KundeID) f
Damit ist die Aufgabe bereits gelöst. (Anmerkung: Es existiert noch ein weiterer Lösungsweg ohne den APPLY Operator, nur ist dieser in diesem Rahmen nicht von Interesse.)
Alternativ zur Verwendung einer Funktion, könnte auch alles in ein einziges SQL-Statement gepackt werden.
SELECT
k.KundeID
,p.ProduktID
,p.P_Umsatz GesUmsatz
FROM (
SELECT TOP 5
t1.KundeID
,SUM(t1.Umsatz) AS K_Umsatz
FROM T_FACT_01_Deckungsbeitragsrechnung t1
GROUP BY t1.KundeID
ORDER BY SUM(t1.Umsatz) DESC
) k
CROSS APPLY
(
SELECT TOP 5
t2.ProduktID
,SUM(t2.Umsatz) AS P_Umsatz
FROM T_FACT_01_Deckungsbeitragsrechnung t2
WHERE t2.KundeID = k.KundeID
GROUP BY t2.ProduktID
ORDER BY SUM(t2.Umsatz) DESC
) p
Die Verwendung des CROSS APPLYS in einem einzigen Statement mit geschachtelten (=Sub-) SELECT Anweisungen ist vielleicht nicht so leicht lesbar, wie der Einsatz einer (gekapselten) Tabellenwertfunktion, allerdings veranschaulicht sie sehr schön, was der CROSS APPLY leistet.
Die „Magie“ im obigen Statement geschieht dabei in der folgenden Zeile:
WHERE t2.KundeID = k.KundeID
Hier ist eine Bedingung formuliert, in welcher der Wert eines Elementes der inneren Menge mit einem Wert der äußeren Menge verglichen wird. Das wäre mit einem JOIN Operator so nicht möglich.
Der APPLY Operator ermöglicht also bei Verwendung von Sub-SELECT Anweisungen sich innerhalb des Sub-SELECTs direkt auf die Werte der äußeren Tabelle zu beziehen und umgekehrt.
Interessanterweise spielt es für den SQL Server keine Rolle, ob wir eine Tabellenwertfunktion verwenden oder nur ein Statement mit Sub-SELECTs verwenden. Die Ausführungspläne sind in beiden Fällen identisch!
Eine weitere Stärke des APPLY Operators liegt in seiner Performance bei der Abarbeitung von Sub-SELECTs. Auch wenn wir keinen Kreuzbezug zwischen innerer und äußerer Tabelle herstellen, so ist der APPLY-Operator dem JOIN-Operator vorzuziehen, da er in der Mehrzahl der Fälle deutlich schneller arbeitet. Der CROSS APPLY arbeitet hierbei ähnlich dem INNER JOIN und der OUTER APPLY entspricht einem LEFT JOIN. Der OUTER APPLY liefert auch die Datensätze der äußeren Tabelle zurück, für die die Tabellenwertfunktion oder das Sub-SELECT keine Datensätze ermitteln kann.
Ob bei der Ersetzung eines JOIN durch den APPLY-Operator eine Performancesteigerung erreicht wer-den kann und wie groß diese ist, darüber gibt der Ausführungsplan des SQL Server Management Studios genauere Aufschlüsse.
Begriffsklärung:
Tabellenwertfunktionen sind Funktionen, die einen Table-Datentyp zurückgeben können. Im Gegensatz zu Sichten (Views) sind diese nicht auf eine einzelne SELECT-Anweisung beschränkt, sondern können zusätzliche Anweisungen und Parameter enthalten, was ihnen eine leistungsfähigere Logik ermöglicht. Neben dem Table-Datentyp kann die Tabellenwertfunktion auch nur einen einzelnen Datentyp zurück-geben. In diesem Fall ist der Datentyp des Rückgabewertes zu spezifizieren. Nähere Informationen hier-zu liefert die T-SQL Dokumentation unter CREATE FUNCTION.
Quellen:
[1] Microsoft TechNet https://docs.microsoft.com/de-de/.)
[2] simple talk – redgate (https://www.simple-talk.com/sql/t-sql-programming/…)
[3] https://www.mssqltips.com/…