SOQL 和 SOSL 查询

您可以评估 Salesforce 对象查询语言 (SOQL) 或 Salesforce 对象搜索 语言 (SOSL) 语句在 Apex 中动态,方法是将语句括在正方形中 括弧。

SOQL 语句

SOQL 语句的计算结果为方法查询的 sObjects、单个 sObject 或 Integer 列表。count例如,您可以检索名为 顶点:

List<Account> aa = [SELECT Id, Name FROM Account WHERE Name = 'Acme'];

从 此列表,您可以访问个人 元素:

if (!aa.isEmpty()) {
   // Execute commands
}

您还可以从现有对象的 SOQL 查询创建新对象。这个例子 为第一个客户创建一个新联系人,其员工数量较多 比 10.

Contact c = new Contact(Account = [SELECT Name FROM Account 
    WHERE NumberOfEmployees > 10 LIMIT 1]);
c.FirstName = 'James';
c.LastName = 'Yoyce';

这 新创建的对象包含其字段的 NULL 值,必须设置这些值。该方法可用于返回 查询返回的行数。以下示例返回总数 姓氏为 魏斯曼:

count

Integer i = [SELECT COUNT() FROM Contact WHERE LastName = 'Weissman'];

你 也可以使用标准对结果进行操作 算术:

Integer j = 5 * [SELECT COUNT() FROM Account];

执行 SOQL 查询时适用 SOQL 限制。请参阅执行调控器和限制。

有关 SOQL 查询语法的完整说明,请参阅 Salesforce SOQL 和 SOSL 参考 指南。

SOSL 声明

SOSL 语句的计算结果为 sObject 列表,其中每个列表都包含 特定 sObject 类型的搜索结果。始终返回结果列表 其顺序与在 SOSL 查询中指定的顺序相同。如果 SOSL 查询没有 返回指定 sObject 类型的任何记录,搜索结果中包括一个空的 该 sObject 的列表。例如,您可以返回客户、联系人、商机和潜在顾客的列表 以短语开头 地图:

List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];

注意Apex 中子句的语法不同于 SOAP API 和 REST API 中子句的语法:

FINDFIND

  • 在 Apex 中,子句的值用单引号分隔。为 例:FINDFIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead注意
  • 在 API 中,子句的值用大括号分隔。为 例:FINDFIND {map*} IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead

顶点 在系统模式下运行会忽略字段级安全性,而 使用 扫描匹配项。IN ALL FIELDS从 中,您可以为 每个对象 返回:

searchList

Account [] accounts = ((List<Account>)searchList[0]);
Contact [] contacts = ((List<Contact>)searchList[1]);
Opportunity [] opportunities = ((List<Opportunity>)searchList[2]);
Lead [] leads = ((List<Lead>)searchList[3]);

执行 SOSL 查询时适用 SOSL 限制。请参阅执行调控器和限制。

有关 SOSL 查询语法的完整说明,请参阅 Salesforce SOQL 和 SOSL 参考 指南。

  1. 使用 SOQL 和 SOSL 查询结果
  2. 通过关系访问 sObject 字段
  3. 了解外键和父子关系 SOQL 查询
  4. 使用 SOQL 聚合函数
  5. 使用非常大的 SOQL 查询
  6. 使用返回一条记录的 SOQL 查询
  7. 通过避免 null 值来提高性能
  8. 在 SOQL 查询
    中使用多态关系 多态关系是对象之间的关系,其中引用的对象可以是几种不同类型的类型之一。例如,任务的关系字段可以是联系人或潜在顾客。Who
  9. 在 SOQL 和 SOSL 查询中使用 Apex 变量
  10. 使用 SOQL 语句查询所有记录

使用 SOQL 和 SOSL 查询结果

SOQL 和 SOSL 查询仅返回 sObject 字段的数据 在原始查询中被选中。如果您尝试访问的字段 未在 SOQL 或 SOSL 查询中选择(ID 除外),您会收到 运行时错误,即使该字段包含数据库中的值也是如此。 下面的代码示例会导致运行时错误:

insert new Account(Name = 'Singha');
Account acc = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1];
// Note that name is not selected
String name = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1].Name;

以下是重写的相同代码示例,因此它不会 产生运行时错误。请注意,已作为 select 语句的一部分添加在 之后。NameId

insert new Account(Name = 'Singha');
Account acc = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1];
// Note that name is now selected
String name = [SELECT Id, Name FROM Account WHERE Name = 'Singha' LIMIT 1].Name;

即使只选择了一个 sObject 字段,SOQL 或 SOSL 查询 始终将数据作为完整记录返回。因此,您必须取消引用 该字段以访问它。例如,此代码检索 带有 SOQL 查询的数据库中的 sObject 列表,访问 列表中的第一个客户记录,然后取消引用记录的字段:AnnualRevenue

Double rev = [SELECT AnnualRevenue FROM Account
              WHERE Name = 'Acme'][0].AnnualRevenue;

// When only one result is returned in a SOQL query, it is not necessary
// to include the list's index.
Double rev2 = [SELECT AnnualRevenue FROM Account
              WHERE Name = 'Acme' LIMIT 1].AnnualRevenue;

唯一没有必要取消引用的情况 SOQL 查询结果中的 sObject 字段,是当查询 返回一个 Integer 作为操作的结果:COUNT

Integer i = [SELECT COUNT() FROM Account];

SOSL 查询返回的记录中的字段必须始终取消引用。

另请注意,包含公式的 sObject 字段在 发出了 SOQL 或 SOSL 查询。对公式中使用的其他字段所做的任何更改都不会 反映在公式字段值中,直到记录在 Apex 中保存并重新查询。喜欢 其他只读 sObject 字段,则公式字段本身的值不能在 顶点。

通过关系访问 sObject 字段

sObject 记录表示与其他记录的关系,具有两个字段:ID 和 地址,指向关联 sObject 的表示形式。例如, Contact sObject 具有 键入 ID 和 Account 类型的字段 指向关联的 sObject 记录本身。AccountIdAccount

ID 字段可用于更改与联系人关联的帐户, 而 sObject 引用字段可用于访问帐户中的数据。这 reference 字段仅作为 SOQL 或 SOSL 查询的结果进行填充(请参阅注释)。

例如,以下 Apex 代码显示了如何关联客户和联系人 ,然后如何使用联系人来修改 帐户:

注意

为了提供最完整的示例,此代码使用了一些描述的元素 本指南后面部分:

  • 有关 和 的信息,请参见 Insert 语句和 Update 语句。insertupdate
Account a = new Account(Name = 'Acme');
insert a;  // Inserting the record automatically assigns a 
           // value to its ID field
Contact c = new Contact(LastName = 'Weissman');
c.AccountId = a.Id;
// The new contact now points at the new account
insert c;

// A SOQL query accesses data for the inserted contact, 
// including a populated c.account field
c = [SELECT Account.Name FROM Contact WHERE Id = :c.Id];

// Now fields in both records can be changed through the contact
c.Account.Name = 'salesforce.com';
c.LastName = 'Roth';

// To update the database, the two types of records must be 
// updated separately
update c;         // This only changes the contact's last name
update c.Account; // This updates the account name

注意

表达式 ,以及任何其他 遍历关系的表达式,显示略有不同的特征 当它被读取为一个值时,而不是当它被修改时:c.Account.Name

  • 当作为值读取时,如果为 null,则计算结果为 ,但生成 .此设计允许开发人员导航 多个关系,无需检查 null 的乏味 值。c.Accountc.Account.NamenullNullPointerException
  • 修改时,如果是 null,则生成一个 .c.Accountc.Account.NameNullPointerException

在 SOSL 中,您可以以与 SELECT 类似的方式访问插入的联系人的数据 上一个 SOQL 中使用的语句 例。

List<List<SObject>> searchList = [FIND 'Acme' IN ALL FIELDS RETURNING Contact(id,Account.Name)]

此外,sObject 字段键可以与 、 一起使用,也可以通过外部 ID 解析外键。为 例:insertupdateupsert

Account refAcct = new Account(externalId__c = '12345');

Contact c = new Contact(Account = refAcct, LastName = 'Kay');

insert c;

这将插入一个具有相等的新联系人,以等于的帐户 到“12345”。如果没有此类帐户,则插入失败。AccountIdexternal_id

提示

以下代码等效于上面的代码。但是,因为它使用 SOQL 查询,效率不高。如果多次调用此代码,它可以 达到最大 SOQL 查询数的执行限制。查看更多 有关执行限制的信息,请参阅执行调控器和限制。

Account refAcct = [SELECT Id FROM Account WHERE externalId__c='12345'];

Contact c = new Contact(Account = refAcct.Id);

insert c;

了解外键和父子 关系 SOQL 查询

声明 SOQL 查询可以是任何有效的 SOQL 语句,包括外键 和父子记录联接。如果包含外键联接, 生成的 sObject 可以使用正态字段表示法进行引用。 例如:SELECT

System.debug([SELECT Account.Name FROM Contact
              WHERE FirstName = 'Caroline'].Account.Name);

此外,sObject 中的父子关系充当 SOQL 查询也是如此。例如:

for (Account a : [SELECT Id, Name, (SELECT LastName FROM Contacts)
                  FROM Account
                  WHERE Name = 'Acme']) {
     Contact[] cons = a.Contacts;
}

//The following example also works because we limit to only 1 contact
for (Account a : [SELECT Id, Name, (SELECT LastName FROM Contacts LIMIT 1)
                  FROM Account
                  WHERE Name = 'testAgg']) {
     Contact c = a.Contacts;
}

使用 SOQL 聚合函数

SOQL 中的聚合函数(如 和 )允许您在查询中汇总和汇总数据。 有关聚合函数的详细信息,请参阅 Salesforce SOQL 和 SOSL 中的聚合函数 参考指南。SUM()MAX()

您可以在不使用子句的情况下使用聚合函数。例如,您可以使用聚合 函数来查找所有机会的平均金额。GROUP BYAVG()

AggregateResult[] groupedResults
  = [SELECT AVG(Amount)aver FROM Opportunity];
Object avgAmount = groupedResults[0].get('aver');

请注意,任何包含聚合函数的查询都会以 AggregateResult 对象。AggregateResult 是只读 sObject,仅用于查询 结果。

当您将聚合函数与子句一起使用时,它们将成为生成报告的更强大的工具。例如,您可以按广告系列找到所有商机的平均金额。GROUP BY

AggregateResult[] groupedResults
  = [SELECT CampaignId, AVG(Amount)
      FROM Opportunity
      GROUP BY CampaignId];
for (AggregateResult ar : groupedResults)  {
    System.debug('Campaign ID' + ar.get('CampaignId'));
    System.debug('Average amount' + ar.get('expr0'));
}

列表中没有 别名会自动获取一个隐含的别名,其格式为 ,其中表示 没有显式别名的聚合字段。的值从 0 开始,并且 每个聚合字段的增量,没有显式别名。有关更多信息,请参阅在 Salesforce SOQL 和 SOSL 中将别名与 GROUP BY 结合使用 参考指南。

注意

包含聚合函数的查询仍受 查询行。除每个函数之外的所有聚合函数,或包括每个聚合函数 聚合用作查询行的行,用于限制跟踪。COUNT()COUNT(fieldname)

对于 或 查询,限制计为一个查询行,除非查询 包含一个 GROUP BY 子句,在这种情况下,每个分组使用一个查询行。COUNT()COUNT(fieldname)

使用非常大的 SOQL 查询

重要

在可能的情况下,我们更改了非包容性条款,以符合我们的 平等的公司价值观。我们保留了某些条款,以避免对客户产生任何影响 实现。

SOQL 查询有时会返回如此多的 sObject,以至于堆大小限制为 超出并发生错误。要解决此问题,请改用 SOQL 查询循环,因为它可以处理多个 使用对 和 的内部调用对记录进行批处理。forqueryqueryMore

例如,如果结果太大,则以下语法会导致运行时异常:

Account[] accts = [SELECT Id FROM Account];

请改用 SOQL 查询循环,如以下 以下示例:for

// Use this format if you are not executing DML statements 
// within the for loop
for (Account a : [SELECT Id, Name FROM Account 
                  WHERE Name LIKE 'Acme%']) {
    // Your code without DML statements here
}

// Use this format for efficiency if you are executing DML statements 
// within the for loop
for (List<Account> accts : [SELECT Id, Name FROM Account
                            WHERE Name LIKE 'Acme%']) {
    for (Account a : accts) {
    // Your code here
    }
    update accts;
}

注意

在循环中使用 SOQL 查询 降低了达到堆大小限制的可能性。但是,这种方法可以 导致 DML 调用增加,导致使用的 CPU 周期更多。有关详细信息,请参阅 SOQL For 循环与标准 SOQL 查询。for

以下示例演示了用于批量更新记录的 SOQL 查询循环。假设你想 在记录中更改其名字和姓氏的联系人的联系人的姓氏 匹配指定条件:for

public void massUpdate() {
    for (List<Contact> contacts:
      [SELECT FirstName, LastName FROM Contact]) {
        for(Contact c : contacts) {
            if (c.FirstName == 'Barbara' &&
              c.LastName == 'Gordon') {
                c.LastName = 'Wayne';
            }
        }
        update contacts;
    }
}

不是在循环中使用 SOQL 查询,而是 批量更新记录的首选方法是使用批处理 Apex,这样可以最大限度地降低达到调速器限制的风险。for

有关更多信息,请参阅 SOQL For 循环。

更高效的 SOQL 查询

为了获得最佳性能,SOQL 查询必须是有选择性的,尤其是对于内部的查询 触发器。为了避免长时间的执行,系统可以终止非选择性 SOQL 查询。当触发器中的非选择性查询时,开发人员会收到错误消息 对包含超过 100 万条记录的对象执行。为了避免这种情况 错误,请确保查询是有选择性的。选择性 SOQL 查询条件

  • 当其中一个查询筛选器位于索引上时,查询是有选择性的 字段和查询筛选器会减少生成的行数 低于系统定义的阈值。SOQL 查询的性能 改进了当 WHERE 子句中使用的两个或多个过滤器满足 提到的条件。
  • 选择性阈值为前 100 万条记录的 10%,并且 在前 100 万条记录之后,少于 5% 的记录,最多 最多 333,333 条记录。在某些情况下,例如 作为索引标准字段的查询筛选器,阈值可以 更高。此外,选择性阈值受以下因素的影响 改变。

选择性 SOQL 查询的自定义索引注意事项

  • 默认情况下,以下字段已编制索引。
    • 主键(Id、Name 和 OwnerId 字段)
    • 外键(查找或主从关系 字段)
    • 审核日期(CreatedDate 和 SystemModstamp 字段)
    • RecordType 字段(为以下所有标准对象编制索引 特色他们)
    • 标记为“外部 ID”或“唯一”的自定义字段
  • 默认情况下未编制索引的字段在以下情况下自动编制索引 Salesforce Optimizer 认识到索引可以改进 频繁运行查询的性能。
  • Salesforce 支持可以根据请求添加自定义索引 客户。
  • 无法在以下类型的字段上创建自定义索引: 多选选择列表,多币种中的货币字段 组织、长文本字段、某些公式字段和二进制文件 字段(Blob、文件或加密文本类型的字段。新数据 类型,通常是复杂的类型,会定期添加到 Salesforce, 这些类型的字段并不总是允许自定义索引。
  • 您无法在包含以下内容的公式字段上创建自定义索引 对选择列表字段的函数调用。TEXT
  • 通常,在这些情况下不使用自定义索引。
    • 查询的值超过系统定义的阈值。
    • filter 运算符为负运算符,例如 (或 )、 和 。NOT EQUAL TO!=NOT CONTAINSNOT STARTS WITH
    • 运营商 在过滤器中使用,以及要扫描的行数 超过 333,333 人。操作员需要对 指数。此阈值可能会发生变化。CONTAINSCONTAINS
    • 您正在与空值 () 进行比较。Name != ”
    但是,还有其他复杂的方案,其中自定义 不能使用索引。如果出现以下情况,请联系您的 Salesforce 代表 这些情况未涵盖你的方案,或者如果需要 对非选择性查询的进一步帮助。

选择性 SOQL 查询的示例为了更好地了解对大型对象的查询是否具有选择性, 让我们分析一些查询。对于这些查询,假设有更多 帐户 sObject 的 100 万条记录。这些记录包括 软删除的记录,即仍在回收中的已删除记录 站。查询 1:

SELECT Id FROM Account WHERE Id IN (<list of account IDs>)

该子句位于索引上 字段 (Id)。如果返回更少 记录超过选择性阈值时,则使用索引 on。该指数通常为 当 ID 列表仅包含几条记录时使用。WHERESELECT COUNT() FROM Account WHERE Id IN (<list of account IDs>)Id查询 2:

SELECT Id FROM Account WHERE Name != ''

因为 Account 是一个大对象,即使 Name 已编制索引(主键), 此筛选器返回大部分记录,进行查询 非选择性。查询 3:

SELECT Id FROM Account WHERE Name != '' AND CustomField__c = 'ValueA'

这里 我们必须看看是否有任何过滤器,当单独考虑时,是 选择性。正如我们在前面的示例中看到的,第一个筛选器不是 选择性。因此,让我们关注第二个问题。如果记录计数 返回的 by 低于 选择性阈值,CustomField__c编制索引,则查询为 选择性。SELECT COUNT() FROM Account WHERE CustomField__c = ‘ValueA’

使用返回一条记录的 SOQL 查询

当结果列表仅包含一个 sObject 值时,可以使用 SOQL 查询来分配单个 sObject 值 元素。当表达式的 L 值为单个 sObject 类型时,Apex 会自动将 查询结果列表中的单个 sObject 记录为 L 值。如果为零,则会导致运行时异常 在列表中找到 sObject 或多个 sObject。例如:

List<Account> accts = [SELECT Id FROM Account];

// These lines of code are only valid if one row is returned from
// the query. Notice that the second line dereferences the field from the
// query without assigning it to an intermediary sObject variable.
Account acct = [SELECT Id FROM Account];
String name = [SELECT Name FROM Account].Name;

通过避免 null 值来提高性能

在 SOQL 和 SOSL 查询中,显式筛选出 WHERE 子句允许 Salesforce 提高查询性能。在以下示例中, 值为 null 的任何记录都是 从 搜索。

Thread__c

Public class TagWS {

/* getThreadTags
*
* a quick method to pull tags not in the existing list
*
*/
   public static webservice List<String> 
   getThreadTags(String threadId, List<String> tags) {

      system.debug(LoggingLevel.Debug,tags);

      List<String> retVals = new List<String>();
      Set<String> tagSet = new Set<String>();
      Set<String> origTagSet = new Set<String>();
      origTagSet.addAll(tags);

// Note WHERE clause optimizes search where Thread__c is not null

      for(CSO_CaseThread_Tag__c t : 
         [SELECT Name FROM CSO_CaseThread_Tag__c 
         WHERE Thread__c = :threadId AND
         Thread__c != null]) 

      {
         tagSet.add(t.Name);
      }
      for(String x : origTagSet) { 
   // return a minus version of it so the UI knows to clear it
         if(!tagSet.contains(x)) retVals.add('-' + x);
      }
      for(String x : tagSet) { 
   // return a plus version so the UI knows it's new
         if(!origTagSet.contains(x)) retvals.add('+' + x);
      }

      return retVals;
   }
}

在 SOQL 查询中使用多态关系

多态关系是对象之间的关系,其中引用 对象可以是几种不同的类型之一。例如,任务的关系字段可以是联系人或潜在顾客。

Who

在Apex中使用具有多态关系的SOQL查询的方法如下。 如果需要有关多态关系的更多常规信息,请参阅了解关系字段和 SOQL 和 SOSL 引用中的多态字段。您可以使用引用 Apex 中的多态字段的 SOQL 查询来获取以下结果: 取决于多态字段引用的对象类型。一种方法是过滤 使用 Type 限定符的结果。此示例查询事件 通过“什么”与“帐户”或“商机”相关 田。

List<Event> events = [SELECT Description FROM Event WHERE What.Type IN ('Account', 'Opportunity')];

另一个 方法是在 SOQL 语句。此示例还查询 通过“什么”与“客户”或“商机”相关的事件 田。

TYPEOFSELECT

List<Event> events = [SELECT TYPEOF What WHEN Account THEN Phone WHEN Opportunity THEN Amount END FROM Event];

这些 查询返回 sObject 列表,其中关系字段引用所需的 对象类型。如果需要访问多态关系中的引用对象,可以使用 instanceof 关键字设置为 确定对象类型。以下示例用于确定 Account 或 Opportunity 是否与 事件。

instanceof

Event myEvent = eventFromQuery;
if (myEvent.What instanceof Account) {
    // myEvent.What references an Account, so process accordingly
} else if (myEvent.What instanceof Opportunity) {
    // myEvent.What references an Opportunity, so process accordingly
}

请注意,必须分配查询返回到的引用的 sObject 一个适当类型的变量,然后才能将其传递给另一个方法。这 以下示例

  1. 使用 SOQL 查询Merchandise__c自定义对象的用户或组所有者 使用子句进行查询TYPEOF
  2. 用于确定所有者 类型instanceof
  3. 将所有者对象分配给用户或组类型变量,然后再将其传递给 实用程序方法
public class PolymorphismExampleClass {

    // Utility method for a User
    public static void processUser(User theUser) {
        System.debug('Processed User');
    }
    
    // Utility method for a Group
    public static void processGroup(Group theGroup) {
        System.debug('Processed Group');
    }

    public static void processOwnersOfMerchandise() {
        // Select records based on the Owner polymorphic relationship field
        List<Merchandise__c> merchandiseList = [SELECT TYPEOF Owner WHEN User THEN LastName WHEN Group THEN Email END FROM Merchandise__c];	
        // We now have a list of Merchandise__c records owned by either a User or Group
        for (Merchandise__c merch: merchandiseList) {
            // We can use instanceof to check the polymorphic relationship type
            // Note that we have to assign the polymorphic reference to the appropriate
            // sObject type before passing to a method
            if (merch.Owner instanceof User) {
                User userOwner = merch.Owner;
                processUser(userOwner);
            } else if (merch.Owner instanceof Group) {
                Group groupOwner = merch.Owner;
                processGroup(groupOwner);
            }
        }
    }
}

在 SOQL 和 SOSL 查询中使用 Apex 变量

Apex 中的 SOQL 和 SOSL 语句可以引用 Apex 代码 变量和表达式(如果它们前面有冒号 ()。在 SOQL 中使用局部代码变量 或 SOSL 语句称为绑定。Apex 解析器首先评估 执行 SOQL 或 SOSL 语句之前代码上下文中的局部变量。:捆 表达式可以用作:

  • 子句中的搜索字符串。FIND
  • 子句中的筛选器文本。WHERE
  • 子句中 or 运算符的值,允许对一组动态值进行筛选。请注意, 这对于 ID 或字符串列表特别有用,尽管它适用于 任何类型。INNOT INWHERE
  • 子句中的分部名称。WITH DIVISION
  • 子句中的数值。LIMIT
  • 子句中的数值。OFFSET

例如:

Account A = new Account(Name='xxx');
insert A;
Account B;

// A simple bind
B = [SELECT Id FROM Account WHERE Id = :A.Id];

// A bind with arithmetic
B = [SELECT Id FROM Account 
     WHERE Name = :('x' + 'xx')];

String s = 'XXX';

// A bind with expressions
B = [SELECT Id FROM Account 
     WHERE Name = :'XXXX'.substring(0,3)];

// A bind with INCLUDES clause
B = [SELECT Id FROM Account WHERE :A.TYPE INCLUDES (‘Customer – Direct; Customer – Channel’)];

// A bind with an expression that is itself a query result
B = [SELECT Id FROM Account
     WHERE Name = :[SELECT Name FROM Account
                    WHERE Id = :A.Id].Name];

Contact C = new Contact(LastName='xxx', AccountId=A.Id);
insert new Contact[]{C, new Contact(LastName='yyy', 
                                    accountId=A.id)};

// Binds in both the parent and aggregate queries
B = [SELECT Id, (SELECT Id FROM Contacts
                 WHERE Id = :C.Id)
     FROM Account
     WHERE Id = :A.Id];

// One contact returned
Contact D = B.Contacts;

// A limit bind
Integer i = 1;
B = [SELECT Id FROM Account LIMIT :i];

// An OFFSET bind
Integer offsetVal = 10;
List<Account> offsetList = [SELECT Id FROM Account OFFSET :offsetVal];

// An IN-bind with an Id list. Note that a list of sObjects
// can also be used--the Ids of the objects are used for 
// the bind
Contact[] cc = [SELECT Id FROM Contact LIMIT 2];
Task[] tt = [SELECT Id FROM Task WHERE WhoId IN :cc];

// An IN-bind with a String list
String[] ss = new String[]{'a', 'b'};
Account[] aa = [SELECT Id FROM Account 
                WHERE AccountNumber IN :ss];

// A SOSL query with binds in all possible clauses

String myString1 = 'aaa';
String myString2 = 'bbb';
Integer myInt3 = 11;
String myString4 = 'ccc';
Integer myInt5 = 22;

List<List<SObject>> searchList = [FIND :myString1 IN ALL FIELDS 
                                  RETURNING 
                                     Account (Id, Name WHERE Name LIKE :myString2
                                              LIMIT :myInt3), 
                                     Contact, 
                                     Opportunity, 
                                     Lead 
                                  WITH DIVISION =:myString4 
                                  LIMIT :myInt5];

注意单位不支持 Apex 绑定变量 参数。此查询 不起作用。

DISTANCE

String units = 'mi';
List<Account> accountList = 
    [SELECT ID, Name, BillingLatitude, BillingLongitude 
     FROM Account 
     WHERE DISTANCE(My_Location_Field__c, GEOLOCATION(10,10), :units) < 10];

使用 SOQL 语句查询所有记录

SOQL 语句可以使用关键字查询组织中的所有记录,包括 已删除的记录和存档的活动。例如:

ALL ROWS

System.assertEquals(2, [SELECT COUNT() FROM Contact WHERE AccountId = a.Id ALL ROWS]);

您可以使用 组织的回收站。不能将关键字与关键字一起使用。ALL ROWSALL ROWSFOR UPDATE

SOQL For 循环

SOQL 循环遍历所有 SOQL 查询返回的 sObject 记录。

forSOQL 循环的语法是 也:

for

for (variable : [soql_query]) {
    code_block
}

for (variable_list : [soql_query]) {
    code_block
}

两者 和 必须与 sObject 的类型相同 由 返回。与标准 SOQL 查询一样,该语句可以引用 在其子句中对表达式进行编码 使用语法。为 例:

 variable variable_list soql_query[soql_query]WHERE:

String s = 'Acme';
for (Account a : [SELECT Id, Name from Account
                  where Name LIKE :(s+'%')]) {
    // Your code
}

下面的示例将 SOQL 查询创建列表与 DML 方法相结合。

update

// Create a list of account records from a SOQL query
List<Account> accs = [SELECT Id, Name FROM Account WHERE Name = 'Siebel']; 

// Loop through the list and update the Name field
for(Account a : accs){
   a.Name = 'Oracle';
}

// Update the database
update accs;

SOQL For 循环与标准 SOQL 查询

SOQL 循环不同于标准 SOQL 语句,因为它们用于检索 sObject 的方法。虽然标准 SOQL 和 SOSL 查询中讨论的查询可以检索查询或多个对象记录, SOQL 循环检索所有 sObject,使用 通过调用 SOAP API 的 和 方法进行高效分块。 开发人员可以通过使用 SOQL 循环来处理返回的查询结果,从而避免对堆大小的限制 多条记录。但是,此方法可能会导致使用更多的 CPU 周期。 请参见堆总大小。forcountforqueryqueryMorefor

包含聚合函数的查询不支持 。如果出现以下情况,则会发生运行时异常 使用包含聚合函数的查询,该聚合函数在循环中返回超过 2,000 行。queryMorefor

SOQL For 循环格式

SOQL 循环可以一次处理一个记录 时间使用单个 sObject 变量,或一次使用 sObject 列表:

for

  • 单个 sObject 格式对每个 sObject 记录执行一次循环。因此 它易于理解和使用,但如果您愿意,效率非常低下 在循环体中使用数据操作语言 (DML) 语句。每个 DML 语句结束 一次只能处理一个 sObject。for<code_block>for
  • sObject 列表格式对每个包含 200 个 sObject 的列表执行一次循环。 因此,它更难理解和使用,但 如果必须在循环体中使用 DML 语句,则为最佳选择。每个 DML 语句可以 一次批量处理 sObject 列表。for<code_block>for

For example, the following code illustrates the difference between the two types of SOQL query loops: 

for

// Create a savepoint because the data should not be committed to the database
Savepoint sp = Database.setSavepoint(); 

insert new Account[]{new Account(Name = 'yyy'), 
                     new Account(Name = 'yyy'), 
                     new Account(Name = 'yyy')};

// The single sObject format executes the for loop once per returned record
Integer i = 0;
for (Account tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) {
    i++;
}
System.assert(i == 3); // Since there were three accounts named 'yyy' in the
                       // database, the loop executed three times

// The sObject list format executes the for loop once per returned batch
// of records
i = 0;
Integer j;
for (Account[] tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) {
    j = tmp.size();
    i++;
}
System.assert(j == 3); // The lt should have contained the three accounts
                       // named 'yyy'
System.assert(i == 1); // 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

// Revert the database to the original state
Database.rollback(sp);

注意

  • 和关键字可用于两者 内联查询循环的类型 格式。使用 sObject 列表格式时,跳到下一个 sObject 列表。breakcontinueforcontinue
  • DML 语句一次最多只能处理 10,000 条记录,而 sObject 列出循环进程记录 每批 200 个。因此,如果您要插入、更新或删除 在 sObject 列表循环中,每个返回的记录都有多个记录,可能会遇到 运行时限制的错误。查看执行 调速器和限制。forfor
  • 你可能会得到一个 带有消息 的 SOQL 循环。有时会引发此异常 当访问检索到的大量子记录(200 个或更多)时 sObject,或者在获取此类记录集的大小时。为 例如,以下 SOQL 循环中的查询检索特定帐户的子联系人。如果 此帐户包含 200 多个子联系人,循环中的语句会导致异常。QueryExceptionforAggregate query has too many rows for direct assignment, use FOR loopforforfor (Account acct : [SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account WHERE Id IN ('<ID value>')]) { List<Contact> contactList = acct.Contacts; // Causes an error Integer count = acct.Contacts.size(); // Causes an error }

若要避免出现此异常,请使用循环遍历子项 记录,作为 遵循。

for

for (Account acct : [SELECT Id, Name, (SELECT Id, Name FROM Contacts) 
                    FROM Account WHERE Id IN ('<ID value>')]) { 
    Integer count=0;
    for (Contact c : acct.Contacts) {
        count++;
    }
}