function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SeanGormanSeanGorman 

Trying to use aggregate function with more than one 'group by'

I'm writing a class that fires on insert/update of a trigger on the OpportunityLineItem. This looks at a picklist field (Play__c) on Product2.

When Opportunity products are added (which may be in batches) I need to count the number of each possible variation in the picklist for each account.

Opp 1 has 5 products added. 2 are Red, 2 are Black and one is White. There are a number of fields on the Opp: isRed, isBlack and IsWhite into which those number must go.

My first take is that an aggregate function would do. My Primary key is Oppid and Play__c in order to count Play__c:

AggregateResult[] OppLineItemsPlays = [select OpportunityId, COUNT(id), PricebookEntry.Product2.Play__c
           from OpportunityLineItem
           where OpportunityId in: oppid
           group by OpportunityId, PricebookEntry.Product2.Play__c];
  System.debug('\n ------------------->OppLineItemsPlays = ' + OppLineItemsPlays);

for(AggregateResult OLIPlays: OppLineItemsPlays) {
   opportunityCount.put((ID) OLIPlays.get('OpportunityId'), (Integer)OLIPlays.get('expr0'));
   System.debug('\n ------------------->Opportunity id = ' + OLIPlays.get('OpportunityId'));
   System.debug('\n ------------------->Play__c = ' + OLIPlays.get('Play__c'));
   System.debug('\n ------------------->count = ' + OLIPlays.get('expr0'));
   System.debug('\n ------------------->OLIPlays = ' + OLIPlays);
//  }

This gives me a count of all of the times that each Play has been selected in Products in OLIs and gives me the name of the play.

Here is my issue and its a bit silly: how would you proceed from here?
My thoughts are to create a new map for every variation of Play and then add the Oppid, Count(Play__c). This means that I have to know every possible play (which I do) and can control the creation of new ones (which I can)
Alternatively a map of ids to a map of strings to integers: [map<id, map<string, integer>> opptyPlayCount = new map<id, map<string, integer>>();]


when I get to saving this I have the Oppids.
for(Id opptyId : summedOpptyIds) {
         opps.add(new Opportunity(
          Id = opptyId,
          Booking_Amount__c = totalBookingAmts.get(opptyId)
          isRed = .................
         ));
        }

Subhash GarhwalSubhash Garhwal
Hi,
Before your Aggregate query you need to fill a map
Map<Id, Opportunity> mapOpps = new Map<Id, Opportunity>();

Now fill this map like
mapOpps.put(OpportunityLineItem.OpportunityId, new Opportunity(Id= OpportunityLineItem.OpportunityId, isRed = null, isBlack = null, IsWhite = null));

Now your query like
AggregateResult[] OppLineItemsPlays = [Select OpportunityId oppId, PricebookEntry.Product2.Play__c playName, Count(Id) cnt From OpportunityLineItem Where
OpportunityId IN : mapOpps.keySet() GROUP BY ROLLUP (OpportunityId, PricebookEntry.Product2.Play__c)]

for(AggregateResult aggResult : OppLineItemsPlays) {
 
  //Opportunity Id
  Id oppId = Id.valueOf(String.valueOf(aggResult.get('oppId')));
  String playName = String.valueOf(aggResult.get('playName'));

  //Now check for Play Name
  if(playName == 'Red') {
   mapOpps.get(oppId).isRed = Integer.valueOf(aggResult.get('cnt'));
  } else if(playName == 'Black') {
   mapOpps.get(oppId).isBlack = Integer.valueOf(aggResult.get('cnt'));
  }......
}
  //Check for size
  if(mapOpps.size() > 0)
   update mapOpps.values();