Msg 195: STRING_SPLIT Is Not a Recognized Built-In Function Name
Yesterday, I was writing some Transact SQL to dust off the cobwebs. I got confused when I was playing around with the STRING_SPLIT function, and kept …
Read MoreBy Kendra Little on • 5 min read
Michelle asked a great question:
In your own words, why would one want to use a cross apply operator rather than a join operator? I’m old school, and I’m just not getting why a cross apply would be so much better to use than a join.
Here’s my top 3 favorite uses for CROSS APPLY and OUTER APPLY:
But it can do even more…
It can help you (un) pivot data. Check out Kenneth Fisher’s example here.
Brad Schulz’s post here has code samples for those, plus more things like showing how it can be useful for shredding XML: http://bradsruminations.blogspot.com/2011/04/t-sql-tuesday-017-it-slices-it-dices-it.html
Brad gets a bit jokey at the end of the post, but there’s a lot of valid uses along the way.
The questions in this quiz are based on two tables, created and populated with the following commands:
CREATE TABLE
dbo.t1
(
t1c1 integer IDENTITY PRIMARY KEY
);
CREATE TABLE
dbo.t2
(
t2c1 integer IDENTITY PRIMARY KEY,
t1c1 integer NOT NULL DEFAULT 'foo'
);
GO
INSERT
dbo.t1
DEFAULT VALUES;
GO 5
INSERT
dbo.t2
(
t1c1
)
SELECT TOP (2)
t1.t1c1
FROM dbo.t1 AS t1;
GO
This produces two tables which look like this:


SELECT
ct = COUNT_BIG(*)
FROM dbo.t1 AS t1
CROSS APPLY
(
SELECT
x = 1 / 0
FROM dbo.t2 AS t2
WHERE t2.t1c1 = t1.t1c1
) AS t2;
Answer: The results of COUNT(*) based on an inner join between the two tables
I know, it’s weird, there’s a 1/0 in there which seems like it would produce a divide by zero error! But that bit of code never gets evaluated in this case, and the query runs successfully.
Sometimes a query using APPLY can be “transformed” into a join operation, and this is one of those cases. You can read more about this in Paul White’s article here.
Most of the time, if you want a join, you should use a join. However, it’s definitely useful to know that APPLY can be used this way for when you are reading and editing code written by others.
SELECT
ct = COUNT_BIG(*)
FROM dbo.t1 AS t1
JOIN dbo.t2 AS t2
ON t2.t1c1 = t1.t1c1;
SELECT
ct = COUNT_BIG(*)
FROM dbo.t1 AS t1
CROSS APPLY
(
SELECT
x = 1 / 0
FROM dbo.t2 AS t2
WHERE t2.t1c1 = t1.t1c1
) AS t2;
Answer: yes
In this case, the second query will be rewritten to use an inner join, just like the first query. One method you can use to verify this is to look at the execution plan for both queries (and you can obviously run them and compare the results).
Both queries return a count of 2.
Here are the estimated plans for both queries:

SELECT
ct = COUNT_BIG(*)
FROM dbo.t1 AS t1
JOIN dbo.t2 AS t2
ON t2.t1c1 = t1.t1c1;
SELECT
ct = COUNT_BIG(*)
FROM dbo.t1 AS t1
OUTER APPLY
(
SELECT
x = 1 / 0
FROM dbo.t2 AS t2
WHERE t2.t1c1 = t1.t1c1
) AS t2;
Answer: no
The first query returns the count of 2. The second query returns a count of 5.
This is because the first query is implemented as an inner join, and the second query is implemented as an outer join.
SELECT
d = t2.t1c1 * 2
FROM dbo.t2 AS t2;
SELECT
x.d
FROM dbo.t2 AS t2
CROSS APPLY
(
SELECT
d = t2.t1c1 * 2
) AS x;
Answer: yes
This is an example of using a CROSS APPLY to compute a calculation.
It’s pretty trivial in this case, but I find this can be very useful in the case of complex queries where you refer to the result of a calculation more than once – doing this can allow you to only do the computation in once place and then refer to it many times. Not only can this make the query more readable sometimes, it can limit the errors if you need to change the calculations (because you’re changing it in fewer places.)
Copyright (c) 2025, Catalyze SQL, LLC; all rights reserved. Opinions expressed on this site are solely those of Kendra Little of Catalyze SQL, LLC. Content policy: Short excerpts of blog posts (3 sentences) may be republished, but longer excerpts and artwork cannot be shared without explicit permission.