I'm afraid that SOQL alone isn't capable of doing what you want (heck, I don't know if plain 'old SQL could do that)...at least not exactly in the way you describe.
SOQL does give us the GROUP BY
keyword, but a query looking like this
[SELECT COUNT(Id) FROM CampaignMember GROUP BY ContactId]
But that'll give you a result like this
ContactId| COUNT(Id)
123 | 3
931 | 1
The GROUP BY
keyword makes the result of the query a List<AggregateResult>
(as opposed to a List<CampaignMember>
), and there isn't a way to figure out which 3 records are related to contactId 123 (at least, not without grouping by another field and iterating over the entire result set, which kinda defeats the purpose of your question).
The closest thing we can do to what you describe is to use a parent-child subquery (also called a Left Outer Join).
[SELECT Id, (SELECT CampaignId FROM CampaignMembers) FROM Contacts]Contact]
The result of that would be
ContactId | Contact
123 | Contact(Id = 123, CampaignMembers = List<CampaignMember>{CampaignMember(CampaignId = 1), CampaignMember(CampaignId = 2), CampaignMember(CampaignId = 3)})
931 | Contact(Id = 931, CampaignMembers = List<CampaignMember>{CampaignMember(CampaignId = 1)})
Yes, the entire subquery (inner query) is contained within the SELECT
clausef of the outer query.
Do make a note that when using a parent-child subquery, the "object" that you select from in the inner query is different. Instead of "CampaignMember", we use "CampaignMembers" (the plural).
CampainMembers
is the child relationship name.
In many cases, the child relationship name is simply the plural name of the "child" object (Contacts
, Opportunities
, etc...) though there are exceptions (the child relationship name of the self-relationship on Account
denoted by the ParentId
field is "childAccounts"). If you made a custom relationship field, then you'll need to put __r
on the end of the child relationship name