Loop over Accounts in chunks
Query the org (SOQL) · Intermediate · 15 min · Runs in your Salesforce Developer org · Apex Path
Scenario. A cleanup script must work through many Accounts without first loading them all into one big List.
Use a SOQL for loop to process 201 tagged Accounts in chunks of 200, and see how the two loop forms behave when a query matches nothing.
What you will learn
A SOQL for loop puts the query right in the loop header. Salesforce fetches rows 200 at a time, so a big result never sits in memory at once.
for (List<Account> chunk : [SELECT Id FROM Account]) {
System.debug(chunk.size());
}
for (Account row : [...]) gives you one row at a time instead.
Gotcha. When nothing matches, the one-row form never runs its body. The list form still runs once, with an empty list. It saves heap, not query rows: the 50,000-row limit still applies.
The task
Count 201 tagged Accounts in chunks with a SOQL for loop, then run both loop forms on a query with no matches and count the passes.
Examples:
- 201 tagged Accounts, fetched 200 at a time →
Rows: 201andChunks: 2 - the
OTHER-decoy doesn't start with the tag → not counted - no matches → one-row form gives
Empty loop: 0, list form givesEmpty chunk passes: 1
Requirements:
- Put the query for
Name LIKE :tagPrefixstraight into the loop header:for (List<Account> chunk : [...]). - Count one chunk per loop pass, and add
chunk.size()to the row count. - Run the empty query twice: once as a one-row loop,
for (Account row : [...]), counting passes inemptyCount, and once as a list-form loop, counting passes inemptyChunkCount. - Set each counter to 0 before its loop. The starter uses -1, so a skipped step can't pass by accident.
- Print
Rows:,Chunks:,Empty loop:andEmpty chunk passes:.
Starter code
String tag = 'AS-Q312-' + UserInfo.getUserId() + '-' +
String.valueOf(Datetime.now().getTime());
String tagPrefix = tag + '%';
List<Account> seeded = new List<Account>();
for (Integer i = 1; i <= 201; i++) {
seeded.add(new Account(Name = tag + '-' + i));
}
seeded.add(new Account(Name = 'OTHER-' + tag + '-Decoy'));
insert seeded;
String missingPrefix = tag + '-Missing%';
Integer rowCount = -1;
Integer chunkCount = -1;
Integer emptyCount = -1;
Integer emptyChunkCount = -1;
System.debug('Rows: ' + rowCount);
System.debug('Chunks: ' + chunkCount);
System.debug('Empty loop: ' + emptyCount);
System.debug('Empty chunk passes: ' + emptyChunkCount);
When it passes
The chunk loop runs twice (200 rows, then 1) for 201 rows in total, the decoy is skipped, the one-row loop on the empty query runs zero times, and the list-form loop on it runs once with an empty list.
You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.
‹ Keep busy Account groups · Search safely with dynamic SOQL ›