从 SQL 迁移到 SOQL
本单元面向熟悉 SQL 的 .NET 开发者,通过对比 SQL 与 SOQL,理解 Salesforce 对象、编写查询、过滤与关系查询。
理解对象并构建查询
Salesforce 平台提供强大的数据库。你熟悉 SQL Server 里数据存储在表和行中,而 Salesforce 用对象(object)存储数据。对象包含表的所有功能,还有更多增强:对象由若干字段(field)组成(对应数据库的列),数据存储在对象的记录(record)中(对应行)。
对象有两种类型:
- 标准对象(Standard Objects):Salesforce 自带,如 Account、Contact、Opportunity、Lead。
- 自定义对象(Custom Objects):为存储应用特有信息而创建,如 Merchandise、Orders、Invoices。
对象还有关系字段,定义不同对象记录之间的关联——本质上是主键和外键,但更灵活。对象不仅存储数据,还提供 UI(选项卡、页面布局、相关列表),以及访问管理、验证、公式、历史跟踪等内置功能,无需自己实现 ORM 或 CRUD UI。
对 SQL 开发者来说,SOQL 很熟悉——SELECT、FROM、WHERE、ORDER BY、LIMIT 都一样。关键区别:
- 没有
SELECT *——必须显式指定字段(多租户环境,用FIELDS(ALL)返回你有权限访问的字段)。 - 没有 JOIN 关键字——用点表示法(dot notation)访问关系。
- 自定义字段以
__c结尾。
用 Developer Console 的 Query Editor 构建查询(相当于你的 SQL Server Management Studio):
SELECT Name, Industry, AnnualRevenue FROM Account WHERE Industry = 'Technology' ORDER BY Name ASC LIMIT 10
过滤与关系查询
过滤(Filtering)的运算符和 SQL 一样:=、!=、<、>、<=、>=、IN、NOT IN、LIKE,并用 AND、OR、NOT 组合条件。
关系查询(Relationship Queries)取代了 SQL 的 JOIN,有两种基本类型:
- 子到父(Child-to-Parent):用点表示法访问父对象字段。
SELECT FirstName, LastName, Account.Name FROM Contact(相当于 SQL 的右外连接)。点表示法最多可向上遍历五级。 - 父到子(Parent-to-Children):在 SELECT 里用嵌套子查询。
SELECT Name, (SELECT FirstName, LastName FROM Contacts) FROM Account(相当于左外连接)。注意嵌套查询里的关系名要用复数(Contacts),自定义对象还要加__r后缀。
聚合(Aggregates)和 SQL 很像:AVG()、COUNT()、COUNT_DISTINCT()、MIN()、MAX()、SUM(),配合 GROUP BY 和 HAVING。例如 SELECT Industry, COUNT(Id) FROM Account GROUP BY Industry。注意 SOQL 没有 AS 关键字,字段别名只在聚合查询中可用。
编写 SOSL 查询
本单元学习 SOSL(Salesforce 对象搜索语言)——跨多个对象进行全文文本搜索。
SOSL 语法与子句
要跨多个 sObject 执行基于文本的查询,用 SOSL(Salesforce Object Search Language)。作为 .NET 开发者,你可能熟悉 Microsoft SQL Server 全文搜索(MS FTS)或 Lucene.Net。SOSL 底层就是 Lucene,但 Salesforce 已帮你配置好,无需安装或维护索引——写 SOSL 查询很容易。
FIND {searchTerm} IN SearchGroup RETURNING ObjectType(fields)
SOSL 语法三部分:
- FIND 子句:必需,后面跟搜索词(单词或短语),支持通配符
*(匹配零个或多个字符)和?(匹配单个字符)。 - IN 子句:指定搜索的字段范围——
ALL FIELDS、NAME FIELDS、EMAIL FIELDS、PHONE FIELDS。注意「ALL FIELDS」并非字面意义上所有字段,对大多数标准/自定义对象默认只搜 name、email、phone、sidebar 字段。 - RETURNING 子句:指定返回哪些对象和字段。
RETURNING Account(Name), Contact(LastName, FirstName)。搜索结果以List<List<SObject>>返回,results[0]是 Account 匹配项、results[1]是 Contact 匹配项。
在 Query Editor 中搜索词用花括号 {joey}(Apex 代码里用单引号)。SOSL 还支持昵称搜索(仅限 Account、Contact、Lead、User 的英文搜索)。
SOQL 还是 SOSL?查询单个对象、知道明确条件用 SOQL;不知道数据在哪个对象、需要跨多个对象搜索用 SOSL(尤其是对象之间不相关时)。
编写高效查询
本单元学习查询优化——Salesforce 查询优化器、构建选择性查询、理解索引,以及用查询计划工具评估性能。
最佳实践与选择性查询
高效的查询不仅性能更好,还能避免触及 governor limits(多租户平台每个同步事务最多 100 条 SOQL 查询、最多检索 50,000 条记录)。查询优化器(Query Optimizer)像交通警察一样把查询路由到合适的索引,为每条查询的每个潜在执行路径分配成本,选择最优执行计划。
构建选择性查询(Selective Query)的关键是在 WHERE 里过滤索引字段,让返回记录数少于总数的 10%。自动索引的字段包括:
Id(主键)、Name、OwnerId、CreatedDate、SystemModStamp(注意它被索引而 LastModifiedDate 没有)。RecordType、主从关系字段、查找关系字段。- 唯一字段(Unique)、外部 ID 字段(External ID)。
要避免的非选择性模式:
- 查询空值:
WHERE Custom_Field__c = null。 - 否定运算符:
!=、NOT LIKE、EXCLUDES。 - 前导通配符:
LIKE '%smi%'(无法用索引)。 - 对文本字段用比较运算符:
>、<等。
选择性 = 快查询 + 低 governor limit 消耗:查询你需要的 100 条记录,而不是 100,000 条不需要的。
查询计划工具
查询计划工具(Query Plan Tool)让你看到查询优化器的幕后工作——相当于 SQL 的 EXPLAIN PLAN。它默认未启用,先在 Developer Console 里通过 Help > Preferences 勾选 Enable Query Plan,Query Editor 里就会出现 Query Plan 按钮。
在 Query Editor 输入查询,点击 Query Plan,可以看到:
- 使用了哪个索引(或显示 TableScan 表示未命中索引)。
- 估算成本(cost)。
- 基数(cardinality,返回多少条记录)。
- 查询是否具有选择性。
对比两条结果相同但性能不同的查询:SELECT Id, CaseNumber FROM Case WHERE Status != 'New' 会触发 TableScan(不好);而 SELECT Id, CaseNumber FROM Case WHERE IsClosed = true 能命中索引(好)。在开发 org 里数据少时差异不明显,但在有数百万记录的 org 里,这个差异是决定性的。
不要靠猜——用 Query Plan 工具测量查询的真实性能。注意它无法评估 SOSL 查询,但 SOSL 也要关注性能。
用 DML 修改记录
最后一个单元学习 DML(数据操作语言)——相当于 SQL 的 INSERT/UPDATE/DELETE,用于管理 Salesforce 记录。
DML 语句与两种执行方式
Salesforce 用 SOQL 查询数据,而管理数据用 DML(Data Manipulation Language)。可用的 DML 语句:
insert— 插入新记录。update— 更新现有记录。upsert— 单条语句内创建新记录或更新现有记录(用指定字段或 ID 判断是否存在)。delete— 删除记录。undelete— 从回收站恢复记录。merge— 合并最多三条同类型记录,删除其余并重新挂接相关记录。
在 Apex 里执行 DML 有两种方式:
- DML 语句(更简单):
insert acct;全有或全无——一条失败则全部回滚。 - Database 类方法(更多控制):
Database.SaveResult[] results = Database.insert(acct, false);可选的allOrNone参数设为 false 时允许部分成功,每条结果都有isSuccess()和getErrors()。
对 SQL 开发者来说,最关键的区别是批量设计:始终对 List 集合操作,绝不要循环处理单条记录——一次处理 200 条记录的 DML 语句只算作 150 条 DML 限额里的 1 条。









