Salesforce uses some confusing terminology around this topic. For clarity...
- An aggregate query (as far as governor limits and error messages seem to go) is a parent-child subquery (a.k.a. a "left outer join" in more standard SQL)
- An aggregate function is something like
COUNT()
,MAX()
,AVG()
, etc...
Aggregate functions can only be applied on the outermost query, and most (if not all) require you to also use GROUP BY
. This causes the query to return a List<AggregateResult>
rather than a List<SObject>
.
Both parent-child subqueries and aggregate functions have their uses. In the particular example that you've given, the advantage of using COUNT()
is that you don't need to worry about the number of records returned. It'll get you the number you're looking for with minimal fuss.
With a parent-child subquery, however, if you have enough child records you won't be able to simply call parent.children.size()
. At a certain point, Salesforce will try to call queryMore
(internally) and you'll be greeted with an error message telling you to iterate over the child records.
That means that your simple parent.children.size()
becomes (pseudocode)
for(parent :[parent query]){
List<child> childList;
for(child :parent.children){
childList.add(child);
}
childList.size();
}
So in this case, the aggregate functions end up being less work (SOQL does more of the work for you). Things like doing your own rollups are a good use case for aggregate functions as well. In other cases, the parent-child subquery approach may make the rest of your code simpler.
At the end of the day, it's about doing whatever makes your life easier. If there's a reasonable way to foist some of the work onto SOQL (or another tool/feature) that would normally be done via apex, it's worth looking into.