INNER JOIN
und CROSS APPLY
(dasselbe gilt für LEFT JOIN
und OUTER APPLY
) sind sehr eng miteinander verbunden. In Ihrem Beispiel würde ich davon ausgehen, dass die Engine den gleichen Ausführungsplan findet.
- Ein
JOIN
ist eine Verknüpfung zwischen zwei Sätzen über eine Bedingung - einen
APPLY
ist eine zeilenweise Unterruf
Aber - wie oben erwähnt - der Optimierer ist sehr schlau und wird - zumindest in solch einfachen Fällen - verstehen, dass es auf dasselbe hinausläuft.
- Der
JOIN
wird versuchen, die Teilmenge zu sammeln und zu verknüpfen über der angegebenen Bedingung - Der
APPLY
versucht, das zugehörige Ergebnis mit den Werten der aktuellen Zeile aufzurufen immer wieder.
Unterschiede bestehen im Aufruf von Tabellenwertfunktionen (sollte inline sein -Syntax!), mit der XML-Methode .nodes()
und mit komplexeren Szenarien.
Ein Beispiel, wie man APPLY
verwenden könnte um Variablen zu simulieren
... um das Ergebnis einer zeilenweisen zu verwenden Berechnung, als ob Sie eine Variable verwenden würden:
DECLARE @dummy TABLE(ID INT IDENTITY, SomeString VARCHAR(100));
INSERT INTO @dummy VALUES('Want to split/this at the two/slashes.'),('And/this/also');
SELECT d.ID
,d.SomeString
,pos1
,pos2
,LEFT(d.SomeString,pos1-1)
,SUBSTRING(d.SomeString,pos1+1,pos2-pos1-1)
,SUBSTRING(d.SomeString,pos2+1,1000)
FROM @dummy AS d
CROSS APPLY(SELECT CHARINDEX('/',d.SomeString) AS pos1) AS x
CROSS APPLY(SELECT CHARINDEX('/',d.SomeString,x.pos1+1) AS pos2) AS y
Dies ist dasselbe wie das Folgende, aber viel einfacher zu lesen (und einzugeben):
SELECT d.ID
,d.SomeString
,LEFT(d.SomeString,CHARINDEX('/',d.SomeString)-1)
,SUBSTRING(d.SomeString,CHARINDEX('/',d.SomeString)+1,CHARINDEX('/',d.SomeString,(CHARINDEX('/',d.SomeString)+1))-(CHARINDEX('/',d.SomeString)+1))
,SUBSTRING(d.SomeString,CHARINDEX('/',d.SomeString,(CHARINDEX('/',d.SomeString)+1))+1,1000)
FROM @dummy AS d
Ein Beispiel mit der XML-Methode .nodes()
DECLARE @dummy TABLE(SomeXML XML)
INSERT INTO @dummy VALUES
(N'<root>
<a>a1</a>
<a>a2</a>
<a>a3</a>
<b>Here is b!</b>
</root>');
SELECT All_a_nodes.value(N'.',N'nvarchar(max)')
FROM @dummy
CROSS APPLY SomeXML.nodes(N'/root/a') AS A(All_a_nodes);
Das Ergebnis
a1
a2
a3
Und ein Beispiel für einen eingebetteten Funktionsaufruf
CREATE FUNCTION dbo.TestProduceRows(@i INT)
RETURNS TABLE
AS
RETURN
SELECT TOP(@i) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nr FROM master..spt_values
GO
CREATE TABLE dbo.TestData(ID INT IDENTITY, SomeString VARCHAR(100),Number INT);
INSERT INTO dbo.TestData VALUES
('Show me once',1)
,('Show me twice',2)
,('Me five times!',5);
SELECT *
FROM TestData
CROSS APPLY dbo.TestProduceRows(Number) AS x;
GO
DROP TABLE dbo.TestData;
DROP FUNCTION dbo.TestProduceRows;
Das Ergebnis
1 Show me once 1 1
2 Show me twice 2 1
2 Show me twice 2 2
3 Me five times! 5 1
3 Me five times! 5 2
3 Me five times! 5 3
3 Me five times! 5 4
3 Me five times! 5 5