How to use SOQL aggregate functions to summarize data and avoid Too Many SOQL Queries: 101?

How to use SOQL aggregate functions to summarize data and avoid Too Many SOQL Queries: 101?

On January 10, 2024, Posted by , In Salesforce, With Comments Off on How to use SOQL aggregate functions to summarize data and avoid Too Many SOQL Queries: 101?

Here’s a code example that demonstrates how to use SOQL aggregate functions to summarize data and avoid the “Too Many SOQL Queries: 101” error in Salesforce:

Scenario:

Suppose you want to find the total number of Opportunities and the total Amount for each Account and update the corresponding fields on the Account record.

Read more: Loops – Salesforce Apex

Original Code (Without Aggregate Functions):

In this original example, a SOQL query retrieves all Opportunity records for each Account, which can lead to exceeding the governor limit if there are many Account records with numerous related Opportunities.

public class AccountOpportunityAggregator {
    public static void updateAccountsWithOpportunityData(List<Account> accounts) {
        for (Account acc : accounts) {
            List<Opportunity> opportunities = [SELECT Id, Amount FROM Opportunity WHERE AccountId = :acc.Id];
            acc.Total_Opportunities__c = opportunities.size();
            Decimal totalAmount = 0;
            for (Opportunity opp : opportunities) {
                totalAmount += opp.Amount;
            }
            acc.Total_Opportunity_Amount__c = totalAmount;
        }
        update accounts;
    }
}

Optimized Code (Using Aggregate Functions):

In the optimized code, SOQL aggregate functions are used to calculate the total number of Opportunities and the total Amount directly in the query, reducing the number of records retrieved and avoiding the need for multiple queries.

public class AccountOpportunityAggregator {
    public static void updateAccountsWithOpportunityData(List<Account> accounts) {
        // Step 1: Collect all Account IDs
        Set<Id> accountIds = new Set<Id>();
        for (Account acc : accounts) {
            accountIds.add(acc.Id);
        }

        // Step 2: Use aggregate functions to summarize Opportunity data
        Map<Id, Account> accountMap = new Map<Id, Account>();
        for (AggregateResult result : [SELECT AccountId, COUNT(Id) oppCount, SUM(Amount) totalAmount 
                                        FROM Opportunity 
                                        WHERE AccountId IN :accountIds 
                                        GROUP BY AccountId]) {
            Id accountId = (Id)result.get('AccountId');
            Account acc = new Account(
                Id = accountId,
                Total_Opportunities__c = (Integer)result.get('oppCount'),
                Total_Opportunity_Amount__c = (Decimal)result.get('totalAmount')
            );
            accountMap.put(accountId, acc);
        }

        // Step 3: Update Accounts with aggregated data
        List<Account> accountsToUpdate = new List<Account>();
        for (Account acc : accounts) {
            if (accountMap.containsKey(acc.Id)) {
                Account aggregatedData = accountMap.get(acc.Id);
                acc.Total_Opportunities__c = aggregatedData.Total_Opportunities__c;
                acc.Total_Opportunity_Amount__c = aggregatedData.Total_Opportunity_Amount__c;
                accountsToUpdate.add(acc);
            }
        }
        update accountsToUpdate; // Perform a single DML operation
    }
}

In this optimized code, a single SOQL query with aggregate functions is used to retrieve the summary data for all Account records in the batch. This significantly reduces the number of queries and records processed, helping to avoid the “Too Many SOQL Queries: 101” error.

Read more: Collections in Salesforce Apex

Comments are closed.