Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Когато отидем за кръстосано прилагане и когато отидем за вътрешно присъединяване в SQL Server 2012

INNER JOIN и CROSS APPLY (същото с LEFT JOIN и OUTER APPLY ) са много тясно свързани. Във вашия пример бих предположил, че двигателят ще намери същия план за изпълнение.

  • JOIN е връзка между два набора над условие
  • APPLY е редово подповикване

Но - както споменахме по-горе - оптимизаторът е много умен и ще разбере - поне в такива лесни случаи - че всичко се свежда до същото.

  • JOIN ще се опита да събере подмножеството и да го свърже над посоченото условие
  • APPLY ще се опита да извика свързания резултат със стойностите на текущия ред отново и отново.

Разликите са в извикването на функции с таблична стойност (трябва да е вграден -синтаксис!), с XML-метод .nodes() и с по-сложни сценарии.

Един пример как може да се използва APPLY за симулиране на променливи

...за да използвате резултата от редове изчисление, както бихте използвали променлива:

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

Това е същото като следното, но много по-лесно за четене (и въвеждане):

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

Един пример с 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);

Резултатът

a1
a2
a3

И един пример за извикване на вградена функция

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;

Резултатът

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да съхранявате исторически записи в таблица с история в SQL Server

  2. Не може да се намери сървър „DB име“ в sys.servers (не е проблем с dbo)

  3. T-SQL и клаузата WHERE LIKE %Parameter%.

  4. Как да добавите ограничение на външния ключ към съществуваща таблица в SQL Server - SQL Server / TSQL Урок, част 68

  5. Какво е SQL Server? (Определение, версии, издания)