First time using aggregate functions in SOQL in Apex, and looking for a little bit of help.
I'm trying to pull the "last" campaign membership off a contact in apex so that I can update their status, but last as in Max(Campaign.EndDate) not Max(CreatedDate) from CampaignMember.
My goal is to get a set of campaign memberships that are of the most recent "xyz" campaign, so my query looks like:
List <AggregateResult> mostRecentCMs = [SELECT ContactId, MAX(Id) id, MAX(Campaign.EndDate) FROM CampaignMember
WHERE ContactId = :contactList AND Campaign.Type = 'XYZ' AND Status = 'Responded' GROUP BY ContactId];
but I don't know 1. if that query is right and 2. how to get that list into a set of CampaignMember Ids. My best guess at the latter based off Jeff Douglas' post is as follows, but I don't really understand the cmSet.add((ID)results.get('id')) part. What I'm particularly concerned with is that the Max(Id) is not the same thing as the Id of the CampaignMember record with the Max(Campaign.EndDate).
for(AggregateResult ar : mostrecentCMs){
System.debug(ar.get('ContactId') + '-' + ar.get('id'));
}
for (AggregateResult results : mostrecentCMs){
mqlsToSAL.add((ID)results.get('id'))
}
for(CampaignMember sal : mostRecentCMs){
sal.Status = 'SAL';
toUpdate.add(sal);
}
I got worried based off this post that I should actually be using a subquery instead of an aggregate function, but I don't think that make sense when Campaign isn't a child of CampaignMember.
Can anyone help get me past this roadblock and/or course correct me?
Edit:
Based off Adrian's idea, maybe this should work off the Campaign. Does the below look correct?
List <Campaign> c = [SELECT Id, EndDate,
(SELECT Id FROM CampaignMembers WHERE Status = 'Responded')
FROM Campaign WHERE Type = 'XYZ' AND Id IN
(SELECT CampaignId FROM CampaignMember WHERE ContactId = :contactList)
ORDER BY EndDate desc limit 1];
Set <CampaignMember> mostRecentCMs = new Set <CampaignMember>;
mostRecentCMs.add(c.CampaignMembers);
Set <Id> cmsToUpdate = new Set <Id>;
for (CampaignMember cm : mostRecentCMs){
cmsToUpdate.add(cm.Id);
}
Best Answer
I think you would have an easier time querying
Campaign
directly here:There are a few things going on here:
Left Outer Join
to get the childCampaignMember
records within the same query.Limits.getAggregateQueries()