この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

Newer Version Available

This content describes an older version of this product. View Latest

SOQL For ループ

SOQL for ループは SOQL クエリで返されたすべての sObject レコードを反復します。
SOQL for ループの構文は次のいずれかになります。
1for (variable : [soql_query]) {
2    code_block
3}
または
1for (variable_list : [soql_query]) {
2    code_block
3}
variable および variable_list は、soql_query で返される sObject と同じデータ型である必要があります。標準 SOQL クエリと同様、[soql_query] ステートメントは、: 構文を使用して WHERE 句のコード式を参照することができます。次に例を示します。
1String s = 'Acme';
2for (Account a : [SELECT Id, Name from Account
3                  where Name LIKE :(s+'%')]) {
4    // Your code
5}
次の例では、SOQL クエリからのリストの作成と DML update メソッドを結合します。
1// Create a list of account records from a SOQL query
2List<Account> accs = [SELECT Id, Name FROM Account WHERE Name = 'Siebel']; 
3
4// Loop through the list and update the Name field
5for(Account a : accs){
6   a.Name = 'Oracle';
7}
8
9// Update the database
10update accs;

SOQL For ループと標準 SOQL クエリの比較

SOQL for ループは、sObjects を取得するために使用するメソッドが、標準 SOQL ステートメントとは異なります。「SOQL および SOSL クエリ」で説明する標準クエリはクエリの count または多数のオブジェクトレコードを取得できますが、SOQL for ループは、SOAP API の query メソッドと queryMore メソッドのコールで効率的なチャンクを使用して、すべての sObject を取得します。開発者はヒープサイズの制限を回避できます。その場合は、SOQL for ループを使用して、複数のレコードを返すクエリ結果を処理します。ただし、この方法では、使用される CPU サイクルが増加する場合があります。「ヒープの合計サイズ」を参照してください。

集計関数を含むクエリでは、queryMore をサポートしません。for ループで 2,000 を超える行を返す集計関数を含むクエリを使用すると、実行時例外が発生します。

SOQL For ループの形式

SOQL for ループは、単一の sObject 変数を使用して一度に 1 件のレコードを処理するか、sObject リストを使用して一度に 200 個の sObject を一括処理できます。
  • 単一の sObject 形式は for ループの <code_block> を sObject レコードごとに 1 回実行します。そのため、理解しやすく、簡単に使用できますが、for ループの本文内でデータ操作言語 (DML) ステートメントを使用すると、効率性が大幅に低下します。DML ステートメントは、一度に 1 つの sObject の処理のみを完了します。
  • sObject リスト形式は for ループの <code_block> を 200 件の sObject のリストごとに 1 回実行します。そのため、多少理解しにくく、使用が難しくなりますが、for ループの本文内で DML ステートメントを使用する必要がある場合に最適です。DML ステートメントは、sObject のリストを一括処理します。
たとえば、次のコードは 2 種類の SOQL クエリ for ループの差異を示します。
1// Create a savepoint because the data should not be committed to the database
2Savepoint sp = Database.setSavepoint(); 
3
4insert new Account[]{new Account(Name = 'yyy'), 
5                     new Account(Name = 'yyy'), 
6                     new Account(Name = 'yyy')};
7
8// The single sObject format executes the for loop once per returned record
9Integer i = 0;
10for (Account tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) {
11    i++;
12}
13System.assert(i == 3); // Since there were three accounts named 'yyy' in the
14                       // database, the loop executed three times
15
16// The sObject list format executes the for loop once per returned batch
17// of records
18i = 0;
19Integer j;
20for (Account[] tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) {
21    j = tmp.size();
22    i++;
23}
24System.assert(j == 3); // The lt should have contained the three accounts
25                       // named 'yyy'
26System.assert(i == 1); // Since a single batch can hold up to 200 records and,
27                       // only three records should have been returned, the 
28                       // loop should have executed only once
29
30// Revert the database to the original state
31Database.rollback(sp);
  • break キーワードと continue キーワードは、どちらのインラインクエリ for ループ形式でも使用できます。sObject リスト形式を使用すると、continue は、sObjects の次のリストにスキップします。
  • DML ステートメントは一度に最大 10,000 件のレコードを処理でき、sObject リスト for ループは 200 件のレコードを一括処理します。そのため、sObject リスト for ループで返されたレコードごとに複数のレコードを挿入、更新、または削除する場合、制限のランタイムエラーが発生する可能性があります。「実行ガバナと制限」を参照してください。
  • SOQL for ループで QueryException が発生し、「Aggregate query has too many rows for direct assignment, use FOR loop」というメッセージが表示される可能性があります。この例外は、取得された sObject の大量の子レコード (200 以上) にループ内でアクセスする場合や、このようなレコードセットのサイズを取得する場合に発生することがあります。たとえば、次の SOQL for ループのクエリは、特定の取引先の子取引先責任者を取得します。この取引先に含まれる子取引先責任者が 200 を超える場合は、for ループのステートメントによって例外が発生します。
    1for (Account acct : [SELECT Id, Name, (SELECT Id, Name FROM Contacts) 
    2                    FROM Account WHERE Id IN ('<ID value>')]) { 
    3    List<Contact> contactList = acct.Contacts; // Causes an error
    4    Integer count = acct.Contacts.size(); // Causes an error
    5}
この例外を回避するには、次のように for ループを使用して、子レコードを反復処理します。
1for (Account acct : [SELECT Id, Name, (SELECT Id, Name FROM Contacts) 
2                    FROM Account WHERE Id IN ('<ID value>')]) { 
3    Integer count=0;
4    for (Contact c : acct.Contacts) {
5        count++;
6    }
7}

メモ