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
Kirill YunussovKirill Yunussov 

Basic question - FOR loop construct syntax and usage

Hi,

 

I'm reading the apex language reference, and on page 66, there is a FOR loop construct that I am not familiar with and don't know how to use.  It takes a List of Objects as the first variable, and a SOQL query as a List to iterate over.  Can you please explain provide some examples?  Thank you. 

 

// example in the book:
for (list_of_variables : [soql_query]) {
    code_block
}

// what I attempted to use and got a compiler error
List<Account> accs = [select id, name from Account limit 3];
for(accs : [select id, name from Account limit 5]) {
    //not sure what I have access to in here, so just doing a debug
    system.debug(accs[0].name);
}

// compiler error is:
// expecting an equals sign, found ':'


 

 

 

Link to the document: http://www.salesforce.com/us/developer/docs/apexcode/salesforce_apex_language_reference.pdf#page=66

Best Answer chosen by Admin (Salesforce Developers) 
SarfarajSarfaraj

Sure. First let me give you one simpler version of your code,

for(Account accs : [select id, name from Account limit 10]) {
	//code to use accs
}

Firstly,

[select id, name from Account limit 10]

This gives us a list of Account. Now we are iterating over this list with the for loop. It is equivalent to this,

List<Account> accounts = [select id, name from Account limit 10];
for(Integer i = 0; i < accounts.size(); ++i)
{
Account accs = accounts.get(i); //code to use accs }

Now what you can do with accs: anything you can do with one account record. retrieve any field value, modify it, update it, do some computation or whatever your business requirement is. Example, let me append one number to each account name,

List<Account> accounts = new List<Account>();
for(Account accs : [select id, name from Account limit 10]) { accs.name = accs.name + '5';
accounts.add(accs); }
update accounts;

Now lets go the the weird syntax of the list.The above seems to be fine to meet all my requirement of iterating over a query result. So why we need that funny syntax? The answer is to bulkify my code staying within heap space limitation. You have specified one limit to your soql. What if you use a number as high as 50000. It is allowed to use a number of this magnitude. But if you try to fetch this number of record and process definitely you will go out of heap space. So what this does,

for(List<Account> accs : [select id, name from Account]) {

At runtime this is handled by salesforce. The soql result is sub-devided in chunks of 200. And my for loop is iterating over this list of list. The list of list is never returned as a whole so there is no issue with heap space. Example, let me append one number to each account name,

for(List<Account> accs : [Select Id, Name From Account])
{
for(Account acc : accs)
{ acc.name = acc.name + '5';
}
update accs;
}

The usage for the one with aggregation is also similar.

All Answers

Kirill YunussovKirill Yunussov

Maybe my SOQL query needs to return a list of lists, and i need to declare the "variable list" inside the FOR loop, instead of outside?   I guess something like below, but I am getting an error with that right now.

 

 

for(List<Account> accs : [select id, name, AVG(Total_billed_sales__c) from Account group by ownerId limit 10]) {
	system.debug(accs);
}

 

Kirill YunussovKirill Yunussov

AND another question: what can you do with that LIST inside the FOR loop?  It seems to be working like a simple assignment statement, with no looping over anything.

SarfarajSarfaraj

Hi

You have to write it like this,

for(List<Account> accs : [select id, name from Account limit 5]) {
    //not sure what I have access to in here, so just doing a debug
    system.debug(accs[0].name);
}

The declaration of the variable accs is bound with the for loop syntax. This is the reason for this error. Also the declaration,

List<Account> accs has one restriction, The type should be same as what is returned by the soql query. In the above query the soql result is Account so it will work. But for your second code the type is AggregateResult. Also I am seeing that your query is malformed in this case. You can not select anything that is not grouped or aggregated. This is true for any database query. Use this,

for(List<AggregateResult> accs : [select id, name, AVG(Total_billed_sales__c) from Account group by ownerId, id, name limit 10]) {
	system.debug(accs);
}

 

Kirill YunussovKirill Yunussov

Great, thanks Akram.   What about inside the for loop, how would you use that accs variable?  Can you give an example?

SarfarajSarfaraj

Sure. First let me give you one simpler version of your code,

for(Account accs : [select id, name from Account limit 10]) {
	//code to use accs
}

Firstly,

[select id, name from Account limit 10]

This gives us a list of Account. Now we are iterating over this list with the for loop. It is equivalent to this,

List<Account> accounts = [select id, name from Account limit 10];
for(Integer i = 0; i < accounts.size(); ++i)
{
Account accs = accounts.get(i); //code to use accs }

Now what you can do with accs: anything you can do with one account record. retrieve any field value, modify it, update it, do some computation or whatever your business requirement is. Example, let me append one number to each account name,

List<Account> accounts = new List<Account>();
for(Account accs : [select id, name from Account limit 10]) { accs.name = accs.name + '5';
accounts.add(accs); }
update accounts;

Now lets go the the weird syntax of the list.The above seems to be fine to meet all my requirement of iterating over a query result. So why we need that funny syntax? The answer is to bulkify my code staying within heap space limitation. You have specified one limit to your soql. What if you use a number as high as 50000. It is allowed to use a number of this magnitude. But if you try to fetch this number of record and process definitely you will go out of heap space. So what this does,

for(List<Account> accs : [select id, name from Account]) {

At runtime this is handled by salesforce. The soql result is sub-devided in chunks of 200. And my for loop is iterating over this list of list. The list of list is never returned as a whole so there is no issue with heap space. Example, let me append one number to each account name,

for(List<Account> accs : [Select Id, Name From Account])
{
for(Account acc : accs)
{ acc.name = acc.name + '5';
}
update accs;
}

The usage for the one with aggregation is also similar.

This was selected as the best answer
Kirill YunussovKirill Yunussov

Very good, thank you! :)