编写 SOQL 查询
学习目标
SOQL 入门
Account[] accts = [SELECT Name,Phone FROM Account];
先决条件
本单元中部分查询示例的前提是组织内已存在客户和联系人。在执行查询之前,先创建一些示例数据。
- 从 Developer Console 的 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;
使用查询编辑器
Developer Console 提供查询编辑器控制台,使您能够运行 SOQL 查询并查看结果。查询编辑器提供了一种快速检查数据库的方法。将 SOQL 查询添加到 Apex 代码前,建议先测试 SOQL 查询。当您使用查询编辑器时,您只需提供 SOQL 语句,而不包含围绕它的 Apex 代码。
让我们试着运行以下 SOQL 示例:
- 在 Developer Console 中,单击 Query Editor(查询编辑器)选项卡。
- 将以下内容复制并粘贴到查询编辑器下的第一个框中,然后单击 Execute(执行)。
SELECT Name,Phone FROM Account
组织的所有客户记录都在 Query Results(查询结果)部分显示为包含字段的行。
SOQL 基础语法
以下是 SOQL 基础查询语法:
SELECT fields FROM ObjectName [WHERE Condition]
WHERE 子句是可选的。我们从一个非常简单的查询开始吧。例如,以下查询检索客户,并为每个客户获取 ID 和电话这两个字段。
SELECT Name,Phone FROM Account
查询分为两部分:
-
SELECT Name,Phone
:这部分列出您想要检索的字段。这些字段在逗号分隔列表中的 SELECT 关键字之后指定。或者您可以只指定一个字段,在这种情况下不需要逗号(例如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
时,返回的值是一个客户,而不是数组。
Account oneAccountOnly = [SELECT Name,Phone FROM Account LIMIT 1];
结合所有片段
您可以按照以下顺序在一个查询中组合可选子句:
SELECT Name,Phone FROM Account WHERE (Name = 'SFDC Computing' AND NumberOfEmployees>25) ORDER BY Name LIMIT 10
使用 Developer Console 中的 Execute Anonymous(执行匿名) 窗口在 Apex 中执行以下 SOQL 查询。然后检查调试日志中的调试语句。应该返回一个示例客户。
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 语句以冒号 (:) 开头。在 SOQL 语句中使用局部变量称为绑定。
此示例展示了如何在 WHERE 子句中使用 targetDepartment
变量。
String targetDepartment = 'Wingo'; Contact[] techContacts = [SELECT FirstName,LastName FROM Contact WHERE Department=:targetDepartment];
查询相关记录
Salesforce 中的记录可以通过查找关系或大纲-细节关系进行关联。例如,联系人与客户之间是查找关系。创建或更新联系人时,您可以将其与客户相关联。与同一客户关联的联系人显示在客户页面的相关列表中。与在 Salesforce 用户界面中查看相关记录的方式一样,您可以在 SOQL 中查询相关记录。
要获取与父记录相关的子记录,请为子记录添加内部查询。内部查询的 FROM 子句作用于关系名称而不是 Salesforce 对象名称。此示例包含一个内部查询,用于获取与每个返回的客户关联的所有联系人。FROM 子句指定联系人关系,这是客户中连接客户和联系人的默认关系。
SELECT Name, (SELECT LastName FROM Contacts) FROM Account WHERE Name = 'SFDC Computing'
下一个示例将示例 SOQL 查询嵌入到 Apex 中,并展示如何使用 sObject 中的联系人关系名称从 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 的查询和 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 类型相同。
最好使用 SOQL for 循环的 sObject 列表格式,因为循环对每批 200 个 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