SOQL クエリを作成する
学習の目的
SOQL 入門
Account[] accts = [SELECT Name,Phone FROM Account];
前提条件
この単元の一部のクエリでは、組織に取引先と取引先責任者があることを前提としています。クエリを実行する前に、いくつかのサンプルデータを作成します。
- 開発者コンソールの [Debug (デバッグ)] メニューから [Execute Anonymous (匿名実行)] ウィンドウを開きます。
- ウィンドウに次のスニペットを入力し、[Execute (実行)] をクリックします。
// Add account and related contact Account acct = new Account( Name='SFDC Computing', Phone='(415)555-1212', NumberOfEmployees=50, BillingCity='San Francisco'); insert acct; // Once the account is inserted, the sObject will be // populated with an ID. // Get this ID. ID acctID = acct.ID; // Add a contact to this account. Contact con = new Contact( FirstName='Carol', LastName='Ruiz', Phone='(415)555-1212', Department='Wingo', AccountId=acctID); insert con; // Add account with no contact Account acct2 = new Account( Name='The SFDC Query Man', Phone='(310)555-1213', NumberOfEmployees=50, BillingCity='Los Angeles', Description='Expert in wing technologies.'); insert acct2;
クエリエディターを使用する
開発者コンソールのクエリエディターコンソールでは、SOQL クエリを実行して結果を表示できます。クエリエディターを使用して、すばやくデータベースを調査できます。そのため、SOQL クエリを Apex コードに追加する前のテストに適しています。クエリエディターを使用するときは、前後の Apex コードなしで SOQL ステートメントのみを入力する必要があります。
次の SOQL の例を実行してみましょう。
- 開発者コンソールで [Query Editor (クエリエディター)] タブをクリックします。
- 次のコードをコピーしてクエリエディターの下の最初のボックスに貼り付け、[Execute (実行)] をクリックします。
SELECT Name,Phone FROM Account
組織内のすべての取引先レコードが [Query Results (クエリ結果)] セクションに項目のある行として表示されます。
基本的な SOQL 構文
基本的な SOQL クエリの構文を次に示します。
SELECT fields FROM ObjectName [WHERE Condition]
WHERE 句は省略可能です。まず簡単なクエリから始めましょう。たとえば、次のクエリは取引先を取得し、各取引先の名前項目と電話項目を取得します。
SELECT Name,Phone FROM Account
このクエリは 2 つの部分で構成されます。
-
SELECT Name,Phone
: この部分には、取得する項目がリストされます。項目は、SELECT キーワードの後にカンマ区切りリストで指定します。または、項目を 1 つだけ指定できます。この場合、カンマは不要です (SELECT Phone
など)。 -
FROM Account
: この部分では、取得する標準またはカスタムオブジェクトを指定します。この例では、Account です。Invoice_Statement という名前のカスタムオブジェクトの場合は、Invoice_Statement__c になります。
条件を指定してクエリ結果を絞り込む
組織に複数の取引先がある場合、すべてが返されます。返される取引先を、特定の条件を満たす取引先に制限する場合、この条件を WHERE 句内に追加できます。次の例では、名前が SFDC Computing の取引先のみが取得されます。文字列の比較では、大文字と小文字は区別されません。
SELECT Name,Phone FROM Account WHERE Name='SFDC Computing'
WHERE 句には、論理演算子 (AND、OR) と括弧を使用してグループ化した複数の条件を含めることができます。たとえば、次のクエリは名前が SFDC Computing で、従業員数が 25 より多い取引先をすべて返します。
SELECT Name,Phone FROM Account WHERE (Name='SFDC Computing' AND NumberOfEmployees>25)
次の別の例では、より複雑な条件が指定されています。このクエリは、以下のレコードをすべて返します。
- すべての SFDC Computing 取引先
- 従業員数が 25 よりも多く、請求先市区郡がロサンゼルスであるすべての取引先
SELECT Name,Phone FROM Account WHERE (Name='SFDC Computing' OR (NumberOfEmployees>25 AND BillingCity='Los Angeles'))
クエリ結果に順序を付ける
クエリが実行されると、Salesforce から返されるレコードは特定の順序にはなっていないため、配列内のレコードの順序はクエリを実行するたびに変わる可能性があります。ただし、ORDER BY 句を追加し、レコードの並び替え基準にする項目を指定することで、返されるレコードセットを並び替えることができます。次の例では、取得されたすべての取引先を名前項目に基づいて並び替えます。
SELECT Name,Phone FROM Account ORDER BY Name
デフォルトの並び替え順は、アルファベットの昇順 (ASC を指定) です。前のステートメントは、次のステートメントと同等です。
SELECT Name,Phone FROM Account ORDER BY Name ASC
順序を逆にするには、DESC キーワードを使用して降順にします。
SELECT Name,Phone FROM Account ORDER BY Name DESC
数値項目とテキスト項目を含む、ほとんどの項目に基づいて並び替えできます。リッチテキストや複数選択リストなどの項目に基づく並び替えはできません。
これらの SOQL ステートメントをクエリエディターで試し、返されるレコードの順序が名前項目に基づいてどのように変化するのかを確認してみましょう。
返されるレコード数を制限する
LIMIT n
句を追加すると (n は返されるレコード数)、返されるレコード数を任意の数に制限できます。どのレコードが返されるかは考慮せずにレコードのサブセットを処理することだけが目的の場合は、結果セットを制限すると便利です。たとえば、次のクエリでは返される最初の取引先を取得します。LIMIT 1
を使用する場合、返される値は 1 件の取引先であり、配列ではないので注意してください。
Account oneAccountOnly = [SELECT Name,Phone FROM Account LIMIT 1];
句を組み合わせる
1 つのクエリ内に、省略可能な句を次の順序で組み合わせることができます。
SELECT Name,Phone FROM Account WHERE (Name = 'SFDC Computing' AND NumberOfEmployees>25) ORDER BY Name LIMIT 10
開発者コンソールの [Execute Anonymous (匿名実行)] ウィンドウを使用して、次の Apex 内の SOQL クエリを実行します。実行後、デバッグログでデバッグステートメントを調査します。1 件のサンプル取引先が返されます。
Account[] accts = [SELECT Name,Phone FROM Account WHERE (Name='SFDC Computing' AND NumberOfEmployees>25) ORDER BY Name LIMIT 10]; System.debug(accts.size() + ' account(s) returned.'); // Write all account array info System.debug(accts);
SOQL クエリの変数にアクセスする
Apex の SOQL ステートメントは、前にコロン (:) が付けられた Apex コードの変数と式を参照できます。SOQL ステートメント内でローカル変数を使用することを、バインドと呼びます。
次の例は、WHERE 句内で targetDepartment
変数を使用する方法を示します。
String targetDepartment = 'Wingo'; Contact[] techContacts = [SELECT FirstName,LastName FROM Contact WHERE Department=:targetDepartment];
関連レコードを照会する
Salesforce 内のレコードは、リレーション (参照関係または主従関係) を介して互いにリンクできます。たとえば、取引先責任者には取引先への参照関係があります。取引先責任者を作成または更新するとき、その取引先責任者を取引先に関連付けることができます。同じ取引先に関連付けられている取引先責任者は、取引先のページの関連リストに表示されます。同様に、Salesforce ユーザーインターフェースで関連レコードを表示したり、SOQL で関連レコードをクエリしたりできます。
親レコードに関連する子レコードを取得するには、子レコードへの内部クエリを追加します。内部クエリの FROM 句は、Salesforce オブジェクト名ではなくリレーション名に対して実行されます。次の例には、返される取引先ごとに関連付けられているすべての取引先責任者を取得する内部クエリが含まれます。FROM 句では、Contacts リレーションを指定しています。これは、取引先と取引先責任者をリンクする Account のデフォルトのリレーションです。
SELECT Name, (SELECT LastName FROM Contacts) FROM Account WHERE Name = 'SFDC Computing'
次の例は、サンプル SOQL クエリを Apex に埋め込み、sObject に対して Contacts リレーション名を使用して、SOQL の結果から子レコードを取得する方法を示します。
Account[] acctsWithContacts = [SELECT Name, (SELECT FirstName,LastName FROM Contacts) FROM Account WHERE Name = 'SFDC Computing']; // Get child records Contact[] cts = acctsWithContacts[0].Contacts; System.debug('Name of first associated contact: ' + cts[0].FirstName + ', ' + cts[0].LastName);
ドット表記を使用して子オブジェクト (取引先責任者) から親の項目 (Account.Name) にトラバースできます。たとえば、次の Apex スニペットでは、名が Carol の取引先責任者レコードを照会し、取引先と取引先責任者間のリレーションをトラバースすることで、Carol が関連付けられている取引先の名前を取得できます。
Contact[] cts = [SELECT Account.Name FROM Contact WHERE FirstName = 'Carol' AND LastName='Ruiz']; Contact carol = cts[0]; String acctName = carol.Account.Name; System.debug('Carol\'s account name is ' + acctName);
SOQL for ループを使用してレコードを一括で照会する
SOQL for ループを使用すると、for
ループ内に SOQL クエリを追加できます。SOQL クエリの結果は、ループ内で反復処理できます。SOQL for ループでは、さまざまなメソッドを使用してレコードを取得します。レコードは、SOAP API の query および queryMore メソッドへのコールで効率のよいチャンク分割を使用して取得されます。SOQL for ループを使用することで、ヒープサイズ制限に達するのを回避できます。
for
ループは SOQL クエリで返されたすべての sObject レコードを反復します。SOQL for
ループの構文は次のいずれかになります。for (variable : [soql_query]) { code_block }
for (variable_list : [soql_query]) { code_block }
variable
および variable_list
は、soql_query
で返される sObject と同じデータ型である必要があります。
ループは、200 個の sObject のバッチごとに 1 回実行されるため、SOQL for ループの sObject リスト形式を使用することをお勧めします。そうすることで、レコードのバッチに対する処理や DML 操作の一括実行が可能になり、ガバナ制限に達するのを回避できます。
insert new Account[]{new Account(Name = 'for loop 1'), new Account(Name = 'for loop 2'), new Account(Name = 'for loop 3')}; // The sObject list format executes the for loop once per returned batch // of records Integer i=0; Integer j=0; for (Account[] tmp : [SELECT Id FROM Account WHERE Name LIKE 'for loop _']) { j = tmp.size(); i++; } System.assertEquals(3, j); // The list should have contained the three accounts // named 'yyy' System.assertEquals(1, i); // Since a single batch can hold up to 200 records and, // only three records should have been returned, the // loop should have executed only once