INNER JOIN
et CROSS APPLY
(idem avec LEFT JOIN
et OUTER APPLY
) sont très proches. Dans votre exemple, je suppose que le moteur trouvera le même plan d'exécution.
- Un
JOIN
est un lien entre deux ensembles sur une condition - un
APPLY
est un ligne par ligne sous-appel
Mais - comme mentionné ci-dessus - l'optimiseur est très intelligent et comprendra - au moins dans des cas aussi simples - que cela revient au même.
- Le
JOIN
essaiera de collecter le sous-ensemble et de le lier sur la condition spécifiée - Le
APPLY
essaiera d'appeler le résultat associé avec les valeurs de la ligne actuelle encore et encore.
Les différences résident dans l'appel de table-valued-functions (doit être inline -syntax !), avec la méthode XML .nodes()
et avec des scénarios plus complexes.
Un exemple d'utilisation de APPLY
pour simuler des variables
...pour utiliser le résultat d'un ligne par ligne calcul comme si vous utilisiez une variable :
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
C'est la même chose que ce qui suit, mais beaucoup plus facile à lire (et à taper) :
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
Un exemple avec la méthode XML .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);
Le résultat
a1
a2
a3
Et un exemple pour un appel de fonction en ligne
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;
Le résultat
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