ApexSensei

Drills › Query the org (SOQL)

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: 201 and Chunks: 2
  • the OTHER- decoy doesn't start with the tag → not counted
  • no matches → one-row form gives Empty loop: 0, list form gives Empty chunk passes: 1

Requirements:

  1. Put the query for Name LIKE :tagPrefix straight into the loop header: for (List<Account> chunk : [...]).
  2. Count one chunk per loop pass, and add chunk.size() to the row count.
  3. Run the empty query twice: once as a one-row loop, for (Account row : [...]), counting passes in emptyCount, and once as a list-form loop, counting passes in emptyChunkCount.
  4. Set each counter to 0 before its loop. The starter uses -1, so a skipped step can't pass by accident.
  5. Print Rows:, Chunks:, Empty loop: and Empty 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.

Try this drill free

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 ›