Skip to main content
From 16:00 UTC on January 17, 2026, to 20:00 UTC on January 17, 2026, we will perform planned maintenance on the Trailhead, myTrailhead, and Trailblazer Community sites. During the maintenance, these sites will be unavailable, and users won't be able to access them. Please plan your activities around this required maintenance.

用标准对象创建关系查询

学习目标

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

  • 描述两种关系查询类型。
  • 识别两个对象之间的关系。
  • 用点记法创建子到父查询。
  • 用子查询创建父到子查询。
  • 用子查询筛选查询结果。

跟随 Trail Together 进行学习

进行这一步骤时,想要跟随专家一起学习吗?查看此视频,它是 Trailhead Live 上 Trail Together 系列的一部分。

(此视频片段从 36:18 开始,如果您想要倒回去再次观看步骤的开头部分可以从这里开始。)

关于关系查询

作为 Salesforce 管理员,您已经熟悉了从相关记录提取数据的公式字段。现在您可以应用对象关系知识来编写 SOQL 查询了。

尽管 FROM 子句仅限于一个对象,但是我们可以用关系查询访问两个相关对象。关系查询依赖两个不同对象之间的关系返回来自两个对象的字段。可以把它想成跨对象的查询。

考虑这项要求:

“获取所有联系人的列表,带每个联系人的客户名称。”

我们可以查询联系人对象,但是它没有 Account Name(客户名称)字段。客户名称实际上是与联系人关联的客户的 Name(名称)字段。在一个组织中,您使用公式字段来访问任何相关对象上的某个字段。在 Apex 中,您使用关系查询,但是关系查询的类型取决于两个对象如何互相关联。

备注

Salesforce 正在努力使其术语更具包容性。阅读文章:Salesforce 不断更新技术语言以解决隐性偏见

要获取:

  • 对象的记录且包含相关父对象的字段,请使用子到父查询。
  • 对象的记录且包含相关子对象的字段,请使用父到子查询。

决定采用哪种查询之前,需要知道我们的两个对象,联系人和客户,如何互相关联。哪一个是父对象,哪一个是子对象?

识别对象的关系

作为管理员,您熟悉组织中的主-详细信息关系。主-详细信息关系是一种父到子关系。主对象是父对象,详细信息对象是子对象。如果您想包含在一个查询中的两个对象具有主-详细信息关系,那么您会知道哪个是父对象,哪个是子对象。

备注

主-详细信息关系是一对多的关系。主对象(父对象)可以有许多详细信息对象(子对象),但是每个详细信息对象(子对象)只能有一个主对象(父对象)。

如果您还不熟悉想包含在一个查询中的两个对象,或者您不知道他们如何互相关联,请在对象管理器中研究这些对象。从更有可能是子对象的对象入手,查看它的“字段和关系”。找到可能关联这个父对象的字段名称。

比如,联系人有一个数据类型是 Lookup(Account) 的 AccountId 字段。记住,在代码中我们需要字段名称 (AccountId),而不是字段标签 (Account Name)。

对象管理器中联系人对象的“字段和关系”页面,突出显示一个字段。字段标签为客户名称。字段名称为 AccountId。数据类型为 Lookup(Account)。

在 AccountId 字段的详细信息中,“子级关系名称”是 Contacts(联系人),复数形式。标准对象的关系名称默认是子对象名称的复数形式

联系人对象上 Account Name(客户名称)字段的详细信息,突出显示“子级关系名称”,即 Contacts(联系人)。

“子级关系名称”确认联系人是客户的子对象。它还提供了父到子查询中需要的关系名称(我们将在本单元后面讨论)。

创建子到父查询

现在我们知道联系人和客户是子到父的关系。联系人是子对象,客户是父对象。要想返回所有联系人(子级)以及每个联系人的客户(父级)名称,我们需要一个子到父查询。

在子到父查询中,您查询子对象,用点记法获取来自父对象的字段,如下所示:

SELECT Name, Account.Name FROM Contact

SELECT 语句查询联系人对象。在 SELECT 子句中,Name(名称)是联系人的 Name(名称)字段,而 Account.Name 是与联系人相关的客户的 Name(名称)字段。

创建子到父查询

  1. 在 Developer Console 的查询编辑器中,输入:
    SELECT Name, Account.Name FROM Contact
  2. 单击执行

结果的前六行应该是:

查询结果——总行数:20

名称

Account.Name

Rose Gonzales

Edge Communications

Sean Forbes

Edge Communications

Jack Rogers

Burlington Textiles Corp of America

Pat Stumuller

Pyramid Construction Inc.

Andy Young

Dickenson plc

Tim Barr

Grand Hotels & Resorts Ltd

第二列显示联系人的父对象,也就是客户的名称。

创建父到子查询

现在我们来思考如何查询父对象并获取其子对象的字段。在父到子查询中,我们使用子查询来获取子对象的字段。子查询是括号中的一个 SELECT 语句,嵌套在另一个查询之中。

假设我们的要求是:

“对于每个客户,返回客户名称以及每个相关联系人的姓名。”

当我们读到“每个相关”的时候,我们就知道需要关系查询。因为联系人是客户的子对象,所以我们需要父到子关系查询,父到子查询包含该子对象的子查询。

主查询(对于每个客户,返回客户名称)和子查询(每个相关联系人的姓名)

要求的第一部分,“对于每个客户,返回客户名称”成为主查询,构成完整查询的外部部分。要求的第二部分,“每个相关联系人的姓名”成为子查询,即嵌套在主查询中的内部查询。

首先,我们定义主查询:SELECT Name FROM Account

接下来,我们定义括号里的子查询:(SELECT Name FROM Contact)

然后,我们放置子查询,就像把它当作主查询中的第二个字段一样。我们在 Name(名称)后面加一个逗号,然后插入子查询,如下所示:

SELECT Name, (SELECT Name FROM Contact) FROM Account.子查询:SELECT Name FROM Contact

在子查询中,我们使用的不是相关对象的字段名称,而是子级关系名称。所以最后一步,我们把子查询改成使用子级关系名称 Contacts,而不是对象名称 Contact,如下所示:

SELECT Name, (SELECT Name FROM Contacts) FROM Account.子查询:SELECT Name FROM Contacts

该查询返回客户名称以及所有客户的所有联系人姓名。我们来细分一下。

该查询分三个部分运行:

  1. 查询选择一个客户并获取该客户的 Name(名称)字段。这是主查询(外部查询)。
  2. 接着,查询该客户的相关联系人并获取每个联系人的 Name(名称)字段。这是子查询(内部查询)。
  3. 然后,它继续转到下一个客户,重复这个过程,直到选择了所有客户。

运行父到子查询

  1. 在查询编辑器中,输入:
    SELECT Name, (SELECT Name FROM Contacts) FROM Account
  2. 单击执行

结果的前六行应该看起来是这样的:

查询结果——总行数:12

名称

联系人

Edge Communications

[{"Name":"Rose Gonzalez"},{"Name":"Sean Forbes"}]

Burlington Textiles Corp of America

[{"Name":"Jack Rogers"}]

Pyramid Construction Inc.

[{"Name":"Pat Stumuller"}]

Dickenson plc

[{"Name":"Andy Young"}]

Grand Hotels & Resorts Ltd

[{"Name":"John Bond"},{"Name":"Tim Barr"}]

United Oil & Gas Corp.

[{"Name":"Arthur Song"},{"Name":"Avi Green"},{"Name":"Lauren Boyle"},{"Name":"Stella Pavlova"}]

有意思!“查询结果”窗口显示客户名称以及与每个客户关联的子联系人记录的集合。这种集合很可能看起来很熟悉,因为我们在管理员面向对象的编程模块讨论过映射。

如果您不记得什么是映射,别担心,我们来复习一下。一个映射集合包含以逗号隔开的键-值对。键是字段名,比如 Name(名称)。键后面跟着它的值,比如 Jake Llorrac。键值对由查询与客户相关的联系人的嵌套 SELECT 语句返回。

用子查询筛选

假设我们只想要相关联系人的姓是 Forbes 的客户。这很难办,因为我们要用子对象联系人中的一个值来筛选母对象客户。用同样的方法,我们在主查询中嵌入一个子查询,我们可以在主查询的 WHERE 子句中使用(子对象的)子查询。子查询的结果充当主查询的筛选器。如果您熟悉交叉筛选器,在子查询中添加 WHERE 子句相当于在报表中使用交叉筛选器。

我们从现有查询开始:

SELECT Name, (SELECT Name FROM Contacts) FROM Account

接着,我们需要一个子查询,从姓是 Forbes 的联系人获取 AccountId 字段:

(SELECT AccountId FROM Contact WHERE LastName = 'Forbes')

您可能会疑惑为什么我们需要联系人的 AccountId 字段。我们检查联系人的 AccountId 字段以找到与某个客户关联的联系人。当联系人对象的 AccountId 字段和客户对象的 Id 字段具有相同的值时,联系人与客户关联 (Contact.AccountId = Account.Id)。所以我们查询联系人对象,返回它的 AccountId 值。要选择与联系人关联的客户,我们找到 Id 字段里有那个值的客户即可。

最后,我们把 WHERE 子句添加到主查询中。我们希望仅当客户记录的 Id 出现在子查询返回的联系人的 AccountId 字段中时,才选择这条客户记录。所以我们添加 WHERE Id IN,后面跟子查询,如下所示:

SELECT Name, (SELECT Name FROM Contacts) FROM Account WHERE Id IN (SELECT AccountId FROM Contact WHERE LastName = 'Forbes')

这条查询做四件事。

  1. 找到姓是 Forbes 的联系人并返回每个联系人的 AccountId 字段的值。(WHERE 子句子查询执行该操作。)
  2. 接着,查询在客户的 Id 字段中找到那个 AccountId 值,并获取那个客户的名称。(主 WHERE 子句执行该操作。)
  3. 接着,查询该客户的相关联系人并获取每个联系人的姓名。(主查询的子查询执行该操作。)
  4. 最后,主查询返回相关联系人的姓是 Forbes 的每个客户的名称,并且对于每个客户,返回所有相关联系人的姓名。

运行筛选后的查询

  1. 在查询编辑器中,输入:
    SELECT Name, (SELECT Name FROM Contacts)
    FROM Account
    WHERE Id IN (SELECT AccountId FROM Contact WHERE LastName = 'Forbes')
  2. 单击执行

您的结果如下所示:

查询结果,第 1 列是名称,第 2 列是逗号隔开的联系人姓和名列表。

总结

现在您已经了解如何为标准对象选择并构建正确的关系查询类型了。在下一个单元中,您将学习自定义对象的关系查询。

资源

在 Salesforce 帮助中分享 Trailhead 反馈

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

了解更多 继续分享反馈