Reputation: 83
Does a CROSS APPLY
with an aggregate function return a row even there is no result in the inner expression?
I'm using Sql Server 2012.
Most of the times when I have a
query that requires a derived table I usually use CROSS APPLY
.
I think it's better performance wise, also, I have access to the outside
table so I can perform TOP n for each row that gets joined etc.
Today I came across a very interesting behavior of cross apply which in my eyes it seems like a bug.
I was trying to do an aggregation on some table but I needed the details as well. so I wrote the query without any aggregation then, I tried a cross apply to sum up where the applied tables Id is equal the id of the outer table.
As far I know, if the inner table is
not returning anything then the outer table won't either (CROSS
APPLY
vs OUTER APPLY
), and that's the case when I'm not using
aggregates but when I use the COUNT
function
I get back results even if the inner table doesn't return anything. I tried it
with simple temp tables (see code) and surprisingly I got the same
result.
If I do a GROUP BY
it works fine.
CREATE TABLE #SampleParent (Id INT PRIMARY KEY IDENTITY, ParentName VARCHAR(25))
CREATE TABLE #SampleChildren (Id INT PRIMARY KEY IDENTITY, ParentId INT, ChildName VARCHAR(25))
INSERT INTO #SampleParent
( ParentName )
VALUES ('Bob')
SELECT *
FROM #SampleParent AS sp
CROSS APPLY (SELECT sc.ChildName FROM #SampleChildren AS sc WHERE sc.ParentId = sp.Id) c
WHERE sp.Id = 1
SELECT *
FROM #SampleParent AS sp
CROSS APPLY (SELECT COUNT(sc.ChildName) c FROM #SampleChildren AS sc WHERE sc.ParentId = sp.Id) c
WHERE sp.Id = 1
--GROUP BY
SELECT *
FROM #SampleParent AS sp
CROSS APPLY (SELECT COUNT(sc.ChildName) c FROM #SampleChildren AS sc WHERE sc.ParentId = sp.Id GROUP BY sc.ParentId) c
WHERE sp.Id = 1
So, the question is:
Does a CROSS APPLY
with an aggregate function return a row even there is no result in the inner expression?
Upvotes: 8
Views: 4095
Reputation: 453028
CROSS APPLY
will eliminate outer rows if the inner expression does not return a row.
An aggregate without a GROUP BY
is a scalar aggregate (as opposed to vector aggregate) and (in the absence of a HAVING
clause) always returns one row even if run against an empty table.
e.g. SELECT COUNT(*) FROM EmptyTable
returns a single row with result 0
- not no rows.
So this explains the behaviour you are asking about.
Upvotes: 6