+ Start a Discussion
Vinnie Bacon 14Vinnie Bacon 14 

How can I keep summary values for Accounts while processing Opportunities in a batch?

I'm trying to do something I think is pretty basic.  I want to run a nightly batch that will summarize all of the Closed Won Opportunites by Account.  (Forget the fact that these roll-up by default.  I'm actually doing something different enough where this won't work.)  We have tons of Opportunities and I need to do this in a nightly batch file.  I'm comfortable with batches cranking away on Opportunities, but how would I keep a running tab BY ACCOUNT given that a specific batch might not have all of the Opportunities associated with that Account?
Best Answer chosen by Vinnie Bacon 14
AshishkAshishk
Run the batch on account instead of opportunity, keep the batch size as low as you can.

Do a nested soql on account in execute method, that way you will get all opportunities associated with that account.

All Answers

Steven NsubugaSteven Nsubuga
Use database.stateful 
global class SummarizeAccountOpportunities implements Database.Batchable<sObject>, Database.Stateful{
     global Map<Id, integer> accountOpportunitiesSummary;
According to the documentation:Each execution of a batch Apex job is considered a discrete transaction. For example, a batch Apex job that contains 1,000 records and is executed without the optional scope parameter is considered five transactions of 200 records each.
If you specify Database.Stateful in the class definition, you can maintain state across these transactions. When using Database.Stateful, only instance member variables retain their values between transactions. Static member variables don’t retain their values and are reset between transactions. Maintaining state is useful for counting or summarizing records as they’re processed. For example, suppose your job processed opportunity records. You could define a method in execute to aggregate totals of the opportunity amounts as they were processed.
If you don’t specify Database.Stateful, all static and instance member variables are set back to their original values.


Read more here https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm
 
Vinnie Bacon 14Vinnie Bacon 14
I get that part.  But say I have 100,000 Opportunities to process that may belong to 20,000 different Accounts.  I can't keep a stateful list, or any list for that matter, of the 20,000 Accounts that I'm having to keep a tally for as we process the 100,000 Opportunities.

There has to be a basic way to do this.  What I'm trying to do must apply to many examples.  I'm finding things related to Aggregate Results and Batch processing.  That seems to be what's needed but I'm nowhere near figuring it out just how to do it.
Steven NsubugaSteven Nsubuga
In that case, rather than keeping a stateful list, you can always save data back to Salesforce in a custom object, at the end of each execute method.
The start of each execute method would have you query this custom object for all the Accounts that will be processed in the current batch of Opportunities.  
AshishkAshishk
Run the batch on account instead of opportunity, keep the batch size as low as you can.

Do a nested soql on account in execute method, that way you will get all opportunities associated with that account.
This was selected as the best answer