Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Wenn wir uns für Cross Apply entscheiden und wenn wir uns für Inner Join in SQL Server 2012 entscheiden

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