Skip to main content

编写 SOQL 查询

学习目标

完成本单元后,您将能够:

  • 在 Apex 中编写 SOQL 查询。
  • 使用 Developer Console 中的查询编辑器执行 SOQL 查询。
  • 使用匿名 Apex 执行嵌入 Apex 中的 SOQL 查询。
  • 查询相关记录。
备注

备注

用中文(简体)学习?在中文(简体)Trailhead Playground 中开始挑战,用括号中提供的译文完成挑战。仅复制并粘贴英文值,因为挑战验证基于英文数据。如果在中文(简体)组织中没有成功通过挑战,我们建议您 (1) 将区域设置切换为美国,(2) 按此处说明将语言切换为英文,(3) 再次单击“检查挑战”按钮。

查看 Trailhead 本地化语言徽章详细了解如何利用 Trailhead 译文。

SOQL 入门

要从 Salesforce 读取记录,必须编写查询。Salesforce 提供了 Salesforce 对象查询语言(简称 SOQL),您可以使用 SOQL 来读取保存的记录。SOQL 与标准 SQL 语言类似,但 SOQL 是为 Lightning 平台定制的。

由于 Apex 可直接访问存储在数据库中的 Salesforce 记录,因此可以将 SOQL 查询嵌入到 Apex 代码中,并以简单直接的方式获取结果。当 SOQL 嵌入到 Apex 中时,它被称为内嵌式 SOQL

要在您的 Apex 代码中包含 SOQL 查询,请将 SOQL 语句包装在方括号中,并将返回值分配给 sObject 数组。例如,以下内容将检索具有两个字段(名称和电话号码)的所有客户记录,并返回客户 sObject 数组。

Account[] accts = [SELECT Name,Phone FROM Account];

先决条件

本单元中部分查询示例的前提是组织内已存在客户和联系人。在执行查询之前,先创建一些示例数据。

  1. 从 Developer Console 的 Debug(调试)菜单中打开 Execute Anonymous(执行匿名)窗口。
  2. 在窗口中插入以下片段,然后单击 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;
备注

联系人 sObject 的名称字段是复合字段。是联系人的名字、姓氏、中间名和后缀字段的串联。“设置”中的对象管理器仅列出复合名称字段。但是我们在本单元中的示例 Apex 代码引用了构成复合字段的各个字段。

使用查询编辑器

Developer Console 提供查询编辑器控制台,使您能够运行 SOQL 查询并查看结果。查询编辑器提供了一种快速检查数据库的方法。将 SOQL 查询添加到 Apex 代码前,建议先测试 SOQL 查询。当您使用查询编辑器时,您只需提供 SOQL 语句,而不包含围绕它的 Apex 代码。

让我们试着运行以下 SOQL 示例:

  1. 在 Developer Console 中,单击 Query Editor(查询编辑器)选项卡。
  2. 将以下内容复制并粘贴到查询编辑器下的第一个框中,然后单击 Execute(执行)
SELECT Name,Phone FROM Account

组织的所有客户记录都在 Query Results(查询结果)部分显示为包含字段的行。

SOQL 基础语法

以下是 SOQL 基础查询语法:

SELECT fields FROM ObjectName [WHERE Condition]

WHERE 子句是可选的。我们从一个非常简单的查询开始吧。例如,以下查询检索客户,并为每个客户获取 ID 和电话这两个字段。

SELECT Name,Phone FROM Account

查询分为两部分:

  1. SELECT Name,Phone:这部分列出您想要检索的字段。这些字段在逗号分隔列表中的 SELECT 关键字之后指定。或者您可以只指定一个字段,在这种情况下不需要逗号(例如 SELECT Phone)。
  2. FROM Account:这部分指定您要检索的标准或自定义对象。在本示例中,指定为 Account。对于名为 Invoice_Statement 的自定义对象,则为 Invoice_Statement__c。
备注

进阶学习

与其他 SQL 语言不同,您不能为所有字段指定 *。您必须指定想要明确获取的每个字段。如果您尝试访问 SELECT 子句中未指定的字段,则会出现错误,原因是未检索到该字段。

您不需要在查询中指定 Id 字段,因为无论是否在查询中指定 Id 字段,它都会在 Apex 查询中返回。例如:SELECT Id,Phone FROM AccountSELECT Phone FROM Account 是等效的语句。唯一需要指定 Id 字段的情况是,它是您要检索的唯一字段,因为您必须列出至少一个字段:SELECT Id FROM Account。在查询编辑器中运行查询时,您可能也需要指定 Id 字段,如果不指定,Id 字段将不会在查询结果中显示。

使用条件筛选查询结果

如果组织中包含多个客户,查询结果将返回所有客户。如果要限制返回满足特定条件的客户,则可以通过 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'))







备注

进阶学习

可以使用 LIKE 运算符进行模糊匹配,而不是通过相等运算符 (=) 进行比较。例如,可以使用以下条件检索名称以 SFDC 开头的所有客户:WHERE Name LIKE 'SFDC%'。通配符 % 表示匹配或不匹配任意字符。相反,_ 字符可以用来匹配一个字符。

查询结果排序

执行查询时,不会按特定顺序从 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);
备注

备注

本节中的示例基于标准对象。也可以使用自定义关系将自定义对象链接到一起。自定义关系名称以 __r 后缀结尾。例如,发票报表通过 Invoice_Statement__c 自定义对象上的 Line_Items__r 关系链接到行项目。

使用 SOQL for 循环批量查询记录

使用 SOQL for 循环,可以在 for 循环中包含 SOQL 查询。SOQL 查询的结果可以在循环内迭代。SOQL for 循环使用不同的方法来检索记录 — 通过调用 SOAP API 的查询和 queryMore 方法,使用高效分块来检索记录。通过使用 SOQL for 循环,可以避免达到堆大小的限制。

SOQL for 循环遍历由 SOQL 查询返回的所有 sObject 记录。SOQL for 循环语法是:

for (variable : [soql_query]) {
    code_block
}

或者

for (variable_list : [soql_query]) {
    code_block
}

Variablevariable_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



资源

在 Salesforce 帮助中分享 Trailhead 反馈

我们很想听听您使用 Trailhead 的经验——您现在可以随时从 Salesforce 帮助网站访问新的反馈表单。

了解更多 继续分享反馈