Wat is het belangrijkste doel van het gebruik van CROSS APPLY?
Ik heb gelezen (vaag via berichten op internet) dat CROSS APPLY
efficiënter kan zijn bij het selecteren van grote datasets als je partitioneert. (Pagina komt in me op)
Ik weet ook dat CROSS APPLY
geen UDF als rechtertabel vereist.
In de meeste inner join
-query’s (een-op-veel-relaties), zou ik ze kunnen herschrijven om CROSS APPLY
te gebruiken, maar ze geven me altijd gelijkwaardige uitvoeringsplannen.
Kan iemand me een goed voorbeeld geven van wanneer CROSS APPLY
een verschil maakt in die gevallen waar inner join
ook zal werken?
Bewerken:
Hier is een triviaal voorbeeld, waarbij de uitvoeringsplannen precies hetzelfde zijn. (Laat me er een zien waar ze verschillen en waar CROSS APPLY
sneller/efficiënter is)
create table Company (
companyId int identity(1,1)
, companyName varchar(100)
, zipcode varchar(10)
, constraint PK_Company primary key (companyId)
)
GO
create table Person (
personId int identity(1,1)
, personName varchar(100)
, companyId int
, constraint FK_Person_CompanyId foreign key (companyId) references dbo.Company(companyId)
, constraint PK_Person primary key (personId)
)
GO
insert Company
select 'ABC Company', '19808' union
select 'XYZ Company', '08534' union
select '123 Company', '10016'
insert Person
select 'Alan', 1 union
select 'Bobby', 1 union
select 'Chris', 1 union
select 'Xavier', 2 union
select 'Yoshi', 2 union
select 'Zambrano', 2 union
select 'Player 1', 3 union
select 'Player 2', 3 union
select 'Player 3', 3
/* using CROSS APPLY */
select *
from Person p
cross apply (
select *
from Company c
where p.companyid = c.companyId
) Czip
/* the equivalent query using INNER JOIN */
select *
from Person p
inner join Company c on p.companyid = c.companyId
Antwoord 1, autoriteit 100%
Kan iemand me een goed voorbeeld geven van wanneer CROSS APPLY een verschil maakt in die gevallen waarin INNER JOIN ook werkt?
Zie het artikel in mijn blog voor gedetailleerde prestatievergelijking:
CROSS APPLY
werkt beter voor dingen die geen eenvoudige JOIN
-voorwaarde hebben.
Deze selecteert 3
laatste records van t2
voor elk record van t1
:
SELECT t1.*, t2o.*
FROM t1
CROSS APPLY
(
SELECT TOP 3 *
FROM t2
WHERE t2.t1_id = t1.id
ORDER BY
t2.rank DESC
) t2o
Het kan niet gemakkelijk worden geformuleerd met een inner join
voorwaarde.
Je zou waarschijnlijk zoiets kunnen doen met behulp van CTE
‘s en window-functie:
WITH t2o AS
(
SELECT t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
FROM t2
)
SELECT t1.*, t2o.*
FROM t1
INNER JOIN
t2o
ON t2o.t1_id = t1.id
AND t2o.rn <= 3
, maar dit is minder leesbaar en waarschijnlijk minder efficiënt.
Bijwerken:
Zojuist gecontroleerd.
Master
is een tabel van ongeveer 20,000,000
records met een PRIMARY KEY
op Id
.
Deze zoekopdracht:
WITH q AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM master
),
t AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
)
SELECT *
FROM t
JOIN q
ON q.rn <= t.id
loopt bijna 30
seconden, terwijl deze:
WITH t AS
(
SELECT 1 AS id
UNION ALL
SELECT 2
)
SELECT *
FROM t
CROSS APPLY
(
SELECT TOP (t.id) m.*
FROM master m
ORDER BY
id
) q
is direct.
Antwoord 2, autoriteit 31%
Bedenk dat je twee tafels hebt.
HOOFDTAFEL
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
DETAILS TABEL
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
Er zijn veel situaties waarin we inner join
moeten vervangen door CROSS APPLY
.
1. Voeg twee tabellen samen op basis van TOP n
resultaten
Overweeg of we Id
en Name
moeten selecteren van Master
en de laatste twee datums voor elke Id
van Details table
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
De bovenstaande zoekopdracht genereert het volgende resultaat.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
x------x---------x--------------x-------x
Zie, het genereerde resultaten voor de laatste twee datums met Id
van de laatste twee datums en voegde deze records vervolgens alleen toe in de buitenste query op Id
, wat verkeerd is. Dit zou zowel Ids
1 als 2 moeten retourneren, maar er is slechts 1 geretourneerd omdat 1 de laatste twee datums heeft. Om dit te bereiken, moeten we CROSS APPLY
gebruiken.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
en vormt het volgende resultaat.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
x------x---------x--------------x-------x
Zo werkt het. De query in CROSS APPLY
kan verwijzen naar de buitenste tabel, waar inner join
dit niet kan doen (het genereert een compileerfout). Bij het vinden van de laatste twee datums, wordt het lidmaatschap gedaan binnen CROSS APPLY
d.w.z. WHERE M.ID=D.ID
.
2. Wanneer we inner join
-functionaliteit nodig hebben met behulp van functies.
CROSS APPLY
kan worden gebruikt als vervanging voor inner join
wanneer we een resultaat moeten krijgen van de Master
-tabel en een function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
En hier is de functie
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
wat het volgende resultaat opleverde
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
x------x---------x--------------x-------x
EXTRA VOORDEEL VAN CROSS APPLY
APPLY
kan worden gebruikt als vervanging voor UNPIVOT
. Hier kunnen ofwel CROSS APPLY
of OUTER APPLY
worden gebruikt, die onderling uitwisselbaar zijn.
Bedenk dat je de onderstaande tabel hebt (genaamd MYTABLE
).
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
De vraag staat hieronder.
SELECT DISTINCT ID,DATES
FROM MYTABLE
CROSS APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
wat het resultaat oplevert
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
| 3 | NULL |
x------x-------------x
Antwoord 3, autoriteit 29%
Met
CROSS APPLY
kun je soms dingen doen die je niet kunt doen met inner join
.
Voorbeeld (een syntaxisfout):
select F.* from sys.objects O
inner join dbo.myTableFun(O.name) F
on F.schema_id= O.schema_id
Dit is een syntaxisfout, omdat, bij gebruik met inner join
, tabelfuncties alleen variabelen of constantenals parameters kunnen gebruiken. (D.w.z. de tabelfunctieparameter kan niet afhankelijk zijn van de kolom van een andere tabel.)
Echter:
select F.* from sys.objects O
cross apply ( select * from dbo.myTableFun(O.name) ) F
where F.schema_id= O.schema_id
Dit is legaal.
Bewerken:
Of anders een kortere syntaxis: (door ErikE)
select F.* from sys.objects O
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id
Bewerken:
Opmerking:
Informix 12.10 xC2+ heeft later afgeleide tabellen en Postgresql (9.3+) heeft Laterale subquery’sdie voor een soortgelijk effect kunnen worden gebruikt.
Antwoord 4, autoriteit 6%
Het lijkt mij dat CROSS APPLY een bepaalde leemte kan opvullen bij het werken met berekende velden in complexe/geneste zoekopdrachten, en ze eenvoudiger en leesbaarder kan maken.
Eenvoudig voorbeeld: u hebt een DoB en u wilt meerdere leeftijdsgerelateerde velden presenteren die ook afhankelijk zijn van andere gegevensbronnen (zoals werkgelegenheid), zoals Age, AgeGroup, AgeAtHiring, MinimumRetirementDate, enz. voor gebruik aan uw einde -gebruikerstoepassing (bijvoorbeeld Excel-draaitabellen).
Opties zijn beperkt en zelden elegant:
-
JOIN-subquery’s kunnen geen nieuwe waarden in de dataset introduceren op basis van gegevens in de bovenliggende query (deze moet op zichzelf staan).
-
UDF’s zijn netjes, maar traag omdat ze de neiging hebben om parallelle bewerkingen te voorkomen. En een aparte entiteit zijn kan een goede zaak zijn (minder code) of een slechte zaak (waar is de code).
-
Verbindingstabellen. Soms kunnen ze werken, maar al snel sluit je je aan bij subquery’s met tonnen UNION’s. Grote puinhoop.
-
Maak nog een weergave voor één doel, ervan uitgaande dat er voor uw berekeningen geen gegevens nodig zijn die halverwege uw hoofdquery zijn verkregen.
-
Tussentabellen. Ja … dat werkt meestal, en vaak een goede optie omdat ze kunnen worden geïndexeerd en snel, maar de prestaties kunnen ook afnemen omdat UPDATE-instructies niet parallel zijn en het niet toestaan om formules (hergebruikresultaten) te laten vallen om verschillende velden binnen de dezelfde verklaring. En soms wil je dingen gewoon in één keer doen.
-
query’s nesten. Ja, u kunt op elk moment haakjes op uw hele query plaatsen en deze gebruiken als een subquery waarop u zowel brongegevens als berekende velden kunt manipuleren. Maar je kunt dit alleen zo vaak doen voordat het lelijk wordt. Heel lelijk.
-
Herhalende code. Wat is de grootste waarde van 3 lange (CASE…ELSE…END) statements? Dat wordt leesbaar!
- Zeg tegen je klanten dat ze die verdomde dingen zelf moeten berekenen.
Heb ik iets gemist? Waarschijnlijk, dus voel je vrij om commentaar te geven. Maar goed, CROSS APPLY is een uitkomst in zulke situaties: je voegt gewoon een simpele CROSS APPLY (select tbl.value + 1 as someFormula) as crossTbl
en voilà! Uw nieuwe veld is nu klaar voor gebruik, praktisch alsof het er altijd al was geweest in uw brongegevens.
Waarden geïntroduceerd via CROSS APPLY kunnen…
- worden gebruikt om een of meerdere berekende velden te maken zonder prestatie-, complexiteits- of leesbaarheidsproblemen toe te voegen
- net als bij JOINs kunnen verschillende opeenvolgende CROSS APPLY-instructies naar zichzelf verwijzen:
CROSS APPLY (select crossTbl.someFormula + 1 as someMoreFormula) as crossTbl2
- u kunt waarden gebruiken die zijn geïntroduceerd door een CROSS APPLY in volgende JOIN-voorwaarden
- Als bonus is er het functie-aspect Tabelwaarde
Verdorie, ze kunnen niets doen!
Antwoord 5, autoriteit 2%
Dit is technisch al heel goed beantwoord, maar laat me een concreet voorbeeld geven van hoe het uiterst nuttig is:
Stel dat u twee tabellen heeft, Klant en Bestelling. Klanten hebben veel bestellingen.
Ik wil een weergave maken met details over klanten en de meest recente bestelling die ze hebben gedaan. Met alleen JOINS zou dit wat self-joins en aggregatie vereisen, wat niet mooi is. Maar met Cross Apply is het supereenvoudig:
SELECT *
FROM Customer
CROSS APPLY (
SELECT TOP 1 *
FROM Order
WHERE Order.CustomerId = Customer.CustomerId
ORDER BY OrderDate DESC
) T
Antwoord 6, autoriteit 2%
Cross apply werkt ook goed met een XML-veld. Als u knooppuntwaarden wilt selecteren in combinatie met andere velden.
Als u bijvoorbeeld een tabel heeft met daarin wat xml
<root> <subnode1> <some_node value="1" /> <some_node value="2" /> <some_node value="3" /> <some_node value="4" /> </subnode1> </root>
De zoekopdracht gebruiken
SELECT
id as [xt_id]
,xmlfield.value('(/root/@attribute)[1]', 'varchar(50)') root_attribute_value
,node_attribute_value = [some_node].value('@value', 'int')
,lt.lt_name
FROM dbo.table_with_xml xt
CROSS APPLY xmlfield.nodes('/root/subnode1/some_node') as g ([some_node])
LEFT OUTER JOIN dbo.lookup_table lt
ON [some_node].value('@value', 'int') = lt.lt_id
Retourneert een resultaat
xt_id root_attribute_value node_attribute_value lt_name
----------------------------------------------------------------------
1 test1 1 Benefits
1 test1 4 FINRPTCOMPANY
Antwoord 7
Kruis toepassen kan worden gebruikt om subquery’s te vervangen waar u een kolom van de subquery nodig heeft
subquery
select * from person p where
p.companyId in(select c.companyId from company c where c.companyname like '%yyy%')
hier kan ik de kolommen van de bedrijfstabel niet selecteren
dus, kruis toepassen
select P.*,T.CompanyName
from Person p
cross apply (
select *
from Company C
where p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T
Antwoord 8
Ik denk dat het leesbaarheid moet zijn 😉
CROSS APPLY zal enigszins uniek zijn voor mensen die lezen om hen te vertellen dat er een UDF wordt gebruikt die wordt toegepast op elke rij uit de tabel aan de linkerkant.
Natuurlijk zijn er andere beperkingen waarbij een CROSS APPLY beter wordt gebruikt dan JOIN die andere vrienden hierboven hebben gepost.
Antwoord 9
Hier is een artikel dat het allemaal uitlegt, met hun prestatieverschil en gebruik ten opzichte van JOINS.
SQL Server CROSS APPLY en OUTER APPLY over JOINS
Zoals in dit artikel wordt gesuggereerd, is er geen prestatieverschil tussen beide voor normale samenvoegbewerkingen (INNER EN CROSS).
Het gebruiksverschil ontstaat wanneer u een zoekopdracht als deze moet uitvoeren:
CREATE FUNCTION dbo.fn_GetAllEmployeeOfADepartment(@DeptID AS INT)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM Employee E
WHERE E.DepartmentID = @DeptID
)
GO
SELECT * FROM Department D
CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)
Dat wil zeggen, als je te maken hebt met functie. Dit kan niet worden gedaan met INNER JOIN, wat de fout zou geven “De meerdelige identifier “D.DepartmentID” kan niet worden gebonden.”Hier wordt de waarde doorgegeven aan de functie als elke rij wordt gelezen. Lijkt me cool. 🙂
Antwoord 10
Hier is een korte tutorial die kan worden opgeslagen in een .sql
-bestand en kan worden uitgevoerd in SSMS dat ik voor mezelf heb geschreven om snel mijn geheugen op te frissen over hoe CROSS APPLY
werkt en wanneer te gebruiken:
-- Here's the key to understanding CROSS APPLY: despite the totally different name, think of it as being like an advanced 'basic join'.
-- A 'basic join' gives the Cartesian product of the rows in the tables on both sides of the join: all rows on the left joined with all rows on the right.
-- The formal name of this join in SQL is a CROSS JOIN. You now start to understand why they named the operator CROSS APPLY.
-- Given the following (very) simple tables and data:
CREATE TABLE #TempStrings ([SomeString] [nvarchar](10) NOT NULL);
CREATE TABLE #TempNumbers ([SomeNumber] [int] NOT NULL);
CREATE TABLE #TempNumbers2 ([SomeNumber] [int] NOT NULL);
INSERT INTO #TempStrings VALUES ('111'); INSERT INTO #TempStrings VALUES ('222');
INSERT INTO #TempNumbers VALUES (111); INSERT INTO #TempNumbers VALUES (222);
INSERT INTO #TempNumbers2 VALUES (111); INSERT INTO #TempNumbers2 VALUES (222); INSERT INTO #TempNumbers2 VALUES (222);
-- Basic join is like CROSS APPLY; 2 rows on each side gives us an output of 4 rows, but 2 rows on the left and 0 on the right gives us an output of 0 rows:
SELECT
st.SomeString, nbr.SomeNumber
FROM -- Basic join ('CROSS JOIN')
#TempStrings st, #TempNumbers nbr
-- Note: this also works:
--#TempStrings st CROSS JOIN #TempNumbers nbr
-- Basic join can be used to achieve the functionality of INNER JOIN by first generating all row combinations and then whittling them down with a WHERE clause:
SELECT
st.SomeString, nbr.SomeNumber
FROM -- Basic join ('CROSS JOIN')
#TempStrings st, #TempNumbers nbr
WHERE
st.SomeString = nbr.SomeNumber
-- However, for increased readability, the SQL standard introduced the INNER JOIN ... ON syntax for increased clarity; it brings the columns that two tables are
-- being joined on next to the JOIN clause, rather than having them later on in the WHERE clause. When multiple tables are being joined together, this makes it
-- much easier to read which columns are being joined on which tables; but make no mistake, the following syntax is *semantically identical* to the above syntax:
SELECT
st.SomeString, nbr.SomeNumber
FROM -- Inner join
#TempStrings st INNER JOIN #TempNumbers nbr ON st.SomeString = nbr.SomeNumber
-- Because CROSS APPLY is generally used with a subquery, the subquery's WHERE clause will appear next to the join clause (CROSS APPLY), much like the aforementioned
-- 'ON' keyword appears next to the INNER JOIN clause. In this sense, then, CROSS APPLY combined with a subquery that has a WHERE clause is like an INNER JOIN with
-- an ON keyword, but more powerful because it can be used with subqueries (or table-valued functions, where said WHERE clause can be hidden inside the function).
SELECT
st.SomeString, nbr.SomeNumber
FROM
#TempStrings st CROSS APPLY (SELECT * FROM #TempNumbers tempNbr WHERE st.SomeString = tempNbr.SomeNumber) nbr
-- CROSS APPLY joins in the same way as a CROSS JOIN, but what is joined can be a subquery or table-valued function. You'll still get 0 rows of output if
-- there are 0 rows on either side, and in this sense it's like an INNER JOIN:
SELECT
st.SomeString, nbr.SomeNumber
FROM
#TempStrings st CROSS APPLY (SELECT * FROM #TempNumbers tempNbr WHERE 1 = 2) nbr
-- OUTER APPLY is like CROSS APPLY, except that if one side of the join has 0 rows, you'll get the values of the side that has rows, with NULL values for
-- the other side's columns. In this sense it's like a FULL OUTER JOIN:
SELECT
st.SomeString, nbr.SomeNumber
FROM
#TempStrings st OUTER APPLY (SELECT * FROM #TempNumbers tempNbr WHERE 1 = 2) nbr
-- One thing CROSS APPLY makes it easy to do is to use a subquery where you would usually have to use GROUP BY with aggregate functions in the SELECT list.
-- In the following example, we can get an aggregate of string values from a second table based on matching one of its columns with a value from the first
-- table - something that would have had to be done in the ON clause of the LEFT JOIN - but because we're now using a subquery thanks to CROSS APPLY, we
-- don't need to worry about GROUP BY in the main query and so we don't have to put all the SELECT values inside an aggregate function like MIN().
SELECT
st.SomeString, nbr.SomeNumbers
FROM
#TempStrings st CROSS APPLY (SELECT SomeNumbers = STRING_AGG(tempNbr.SomeNumber, ', ') FROM #TempNumbers2 tempNbr WHERE st.SomeString = tempNbr.SomeNumber) nbr
-- ^ First the subquery is whittled down with the WHERE clause, then the aggregate function is applied with no GROUP BY clause; this means all rows are
-- grouped into one, and the aggregate function aggregates them all, in this case building a comma-delimited string containing their values.
DROP TABLE #TempStrings;
DROP TABLE #TempNumbers;
DROP TABLE #TempNumbers2;
Antwoord 11
Nou, ik weet niet zeker of dit een reden is om Cross Apply versus Inner Join te gebruiken, maar deze vraag is voor mij beantwoord in een forumbericht met Cross Apply, dus ik weet niet zeker of er een gelijkwaardige methode is met Inner Doe mee:
Create PROCEDURE [dbo].[Message_FindHighestMatches]
-- Declare the Topical Neighborhood
@TopicalNeighborhood nchar(255)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
Create table #temp
(
MessageID int,
Subjects nchar(255),
SubjectsCount int
)
Insert into #temp Select MessageID, Subjects, SubjectsCount From Message
Select Top 20 MessageID, Subjects, SubjectsCount,
(t.cnt * 100)/t3.inputvalues as MatchPercentage
From #temp
cross apply (select count(*) as cnt from dbo.Split(Subjects,',') as t1
join dbo.Split(@TopicalNeighborhood,',') as t2
on t1.value = t2.value) as t
cross apply (select count(*) as inputValues from dbo.Split(@TopicalNeighborhood,',')) as t3
Order By MatchPercentage desc
drop table #temp
END
Antwoord 12
De essentie van de APPLY-operator is om correlatie toe te staan tussen de linker- en rechterkant van de operator in de FROM-component.
In tegenstelling tot JOIN is de correlatie tussen invoer niet toegestaan.
Over correlatie gesproken in de APPLY-operator, ik bedoel, aan de rechterkant kunnen we plaatsen:
- een afgeleide tabel – als een gecorreleerde subquery met een alias
- een functie met tabelwaarde – een conceptuele weergave met parameters, waarbij de parameter naar de linkerkant kan verwijzen
Beide kunnen meerdere kolommen en rijen retourneren.
Antwoord 13
Dit is misschien een oude vraag, maar ik ben nog steeds dol op de kracht van CROSS APPLY om het hergebruik van logica te vereenvoudigen en om een “keten”-mechanisme voor resultaten te bieden.
Ik heb hieronder een SQL Fiddle gegeven die een eenvoudig voorbeeld laat zien van hoe je CROSS APPLY kunt gebruiken om complexe logische bewerkingen op je dataset uit te voeren zonder dat het helemaal rommelig wordt. Het is niet moeilijk om van hieruit meer complexe berekeningen te extrapoleren.
http://sqlfiddle.com/#!3/23862/2
Antwoord 14
Hoewel de meeste query’s die gebruikmaken van CROSS APPLY kunnen worden herschreven met een INNER JOIN, kan CROSS APPLY een beter uitvoeringsplan en betere prestaties opleveren, omdat het de set kan beperken voordat de join plaatsvindt.
Gestolen van Hier