Skip to main content
Build the future with Agentforce at TDX in San Francisco or on Salesforce+ on March 5–6. Register now.

用标准对象创建关系查询

学习目标

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

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

跟随 Trail Together 进行学习

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

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

关于关系查询

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

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

考虑这项要求:

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

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

要获取:

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

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

识别对象的关系

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

备注

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

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

比如,联系人有一个数据类型是 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 帮助网站访问新的反馈表单。

了解更多 继续分享反馈