关于 sf-soql
面向 Salesforce 开发者的 SOQL 查询构建与优化指南,涵盖关系查询、聚合、SOSL 和动态 SOQL。重点强调用户模式安全、绑定变量、选择性筛选及常见限制。
主要功能
- 01构建关系与聚合查询
- 02使用 SOSL 进行全文搜索
- 03采用用户模式和绑定变量
- 04识别低效查询模式
- 05利用查询计划分析性能
- 06检查查询限制与语法注意事项
适用场景
- 01编写符合权限控制的 Salesforce 查询
- 02搜索多个对象的文本内容
- 03优化大型数据集的查询
- 04排查查询计划与限制问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ clientell-ai/ salesforce-skills --skill sf-soql安装后在 Claude Code 中输入/sf-soql确认已加载。
附带文件references/soql-reference.md
详细介绍
SOQL 查询构建器与优化器
你是 Salesforce SOQL 专家。构建经过优化且安全的查询。
安全第一
- 始终使用
WITH USER_MODE强制执行 CRUD/FLS - 绝不要使用字符串拼接来构建动态 SOQL——请使用绑定变量
- 只有确实需要动态查询时才使用
Database.query()
// GOOD
List<Account> accounts = [
SELECT Id, Name, Industry
FROM Account
WHERE Industry = :industryFilter
WITH USER_MODE
LIMIT 200
];
// BAD — injection risk
String query = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\'';
查询模式
父级到子级(子查询)
SELECT Id, Name,
(SELECT Id, FirstName, LastName FROM Contacts)
FROM Account
WHERE Industry = 'Technology'
WITH USER_MODE
子级到父级(点表示法)
SELECT Id, FirstName, Account.Name, Account.Industry
FROM Contact
WHERE Account.Industry = 'Technology'
WITH USER_MODE
聚合查询
SELECT Industry, COUNT(Id) cnt, SUM(AnnualRevenue) totalRevenue
FROM Account
WHERE Industry != null
WITH USER_MODE
GROUP BY Industry
HAVING COUNT(Id) > 5
ORDER BY COUNT(Id) DESC
多态(TYPEOF)
SELECT Id, Subject,
TYPEOF What
WHEN Account THEN Name, Industry
WHEN Opportunity THEN Name, StageName, Amount
END
FROM Task
WITH USER_MODE
半连接与反连接
-- Semi-join: Accounts WITH contacts
SELECT Id, Name FROM Account
WHERE Id IN (SELECT AccountId FROM Contact)
WITH USER_MODE
-- Anti-join: Accounts WITHOUT opportunities
SELECT Id, Name FROM Account
WHERE Id NOT IN (SELECT AccountId FROM Opportunity)
WITH USER_MODE
SOSL(搜索语言)
使用 SOSL 跨多个对象进行全文搜索:
FIND {SearchTerm} IN ALL FIELDS
RETURNING Account(Id, Name WHERE Industry = 'Tech'),
Contact(Id, FirstName, LastName)
LIMIT 20
- 适合使用 SOSL 的情况:跨对象搜索文本、模糊匹配、匹配部分词语
- 适合使用 SOQL 的情况:精确匹配、关系查询、聚合、与 DML 相关的查询
- Governor 限制:每个事务最多执行 20 次 SOSL 查询
日期字面量
| 字面量 | 含义 |
|---|---|
TODAY, YESTERDAY, TOMORROW | 日历日 |
THIS_WEEK, LAST_WEEK, NEXT_WEEK | 周日到周六的一周 |
THIS_MONTH, LAST_MONTH, NEXT_MONTH | 日历月 |
THIS_QUARTER, LAST_QUARTER | 日历季度 |
THIS_YEAR, LAST_YEAR, NEXT_YEAR | 日历年 |
LAST_N_DAYS:n | 过去 n 天(包括今天) |
NEXT_N_DAYS:n | 接下来 n 天(包括今天) |
LAST_90_DAYS | 过去 90 天 |
THIS_FISCAL_QUARTER, THIS_FISCAL_YEAR | 财年期间 |
N_DAYS_AGO:n | 恰好 n 天前 |
FIELDS() 函数
SELECT FIELDS(ALL) FROM Account LIMIT 200 -- All fields (LIMIT required)
SELECT FIELDS(STANDARD) FROM Account -- Standard fields only
SELECT FIELDS(CUSTOM) FROM Account -- Custom fields only
动态 SOQL
String query = 'SELECT Id, Name FROM Account WHERE Industry = :industry';
List<Account> results = Database.query(query, AccessLevel.USER_MODE);
- 使用
Database.query()时始终使用AccessLevel.USER_MODE - 使用
:bindVariable语法——绝不要使用字符串拼接 - 对于确实需要动态指定的字段名:使用
String.escapeSingleQuotes()
实用函数
toLabel(PicklistField)— 返回翻译后的选项列表标签FORMAT(NumberField)— 按区域设置格式化数字/日期convertCurrency(Amount)— 转换为用户的货币(多货币组织)
记录锁定
SELECT Id, Name FROM Account WHERE Id = :accountId FOR UPDATE
悲观锁定——阻止其他事务在提交或回滚前更新记录。
ALL ROWS(包括已删除记录)
SELECT Id, Name FROM Account WHERE IsDeleted = true ALL ROWS
返回软删除的记录(在回收站中保留 15 天)。
SOQL 循环
for (List<Account> batch : [SELECT Id, Name FROM Account]) {
// Processes 200 records per iteration automatically
// Uses minimal heap — ideal for large datasets
}
地理位置查询
SELECT Id, Name, DISTANCE(Location__c, GEOLOCATION(37.7749, -122.4194), 'mi') dist
FROM Store__c
WHERE DISTANCE(Location__c, GEOLOCATION(37.7749, -122.4194), 'mi') < 50
ORDER BY DISTANCE(Location__c, GEOLOCATION(37.7749, -122.4194), 'mi')
WITH SECURITY_ENFORCED 与 WITH USER_MODE
| 特性 | SECURITY_ENFORCED | USER_MODE |
|---|---|---|
| FLS 强制执行 | 仅 SELECT/FROM | SELECT/FROM/WHERE/子查询 |
| 发生违规时 | 抛出异常 | 静默移除不可访问的字段 |
| 限制规则 | 不支持 | 支持 |
| 建议 | 旧版——请迁移 | 首选 |
优化规则
选择性筛选条件(使用索引字段)
Id、Name、OwnerId、CreatedDate、SystemModstampRecordTypeId、Lookup字段、External ID字段- 标记为
External ID或具有自定义索引的自定义字段
要识别的反模式
- 循环中执行查询——将查询移到循环之前,使用 Map/Set
- 非选择性筛选条件——优先按索引字段筛选
- 相当于 SELECT *——绝不要选择所有字段,只选择所需字段
- 缺少 LIMIT——对于可能返回大量数据的查询,添加 LIMIT
- 否定筛选条件——
!=和NOT IN都不是选择性的 - 前置通配符——
LIKE '%term'无法使用索引 - 缺少 WHERE 子句——除非有意加载全部数据,否则始终添加筛选条件
查询计划分析
sf data query -q "EXPLAIN SELECT Id FROM Account WHERE Name = 'Test'" --target-org myOrg
限制
- 每个同步事务最多执行 100 次 SOQL 查询
- 每个异步事务最多执行 200 次 SOQL 查询
- 每个事务最多返回 50,000 行
- 子查询最多返回 2,000 行
- 每个父级查询最多执行 20 次关系查询
注意事项
FIELDS(ALL)必须搭配LIMIT 200— 否则会失败COUNT()会统计所有行,包括空值;COUNT(fieldName)只统计非空值FOR UPDATE会锁定整行 — 其他事务会等待或超时- SOSL 有自己的治理限制:每个事务 20 次查询(与 SOQL 的 100 次限制分开计算)
- 日期字面量包含边界日 —
LAST_N_DAYS:7包含今天 TYPEOF仅适用于多态字段(如 Task.What、Event.Who 等)- 子查询结果限制为 2,000 行 — 不是 50,000 行
- Apex 不支持
FIELDS(ALL)— 仅 REST API 和 Developer Console 支持 Database.query()不支持 FIELDS() — 请使用显式字段列表ALL ROWS不能与FOR UPDATE一起使用
工作流
- 了解数据需求
- 检查对象关系和字段类型
- 使用正确的筛选条件、安全设置和限制来构建查询
- 使用以下命令测试:
sf data query -q "YOUR_QUERY" --target-org myOrg - 根据结果和解释计划进行优化
参考资料
- SOQL/SOSL 参考 — 日期字面量、SOSL 语法、FIELDS()、地理位置、动态 SOQL、聚合、FOR UPDATE、绑定模式、查询计划
- 治理限制 — 每个事务的 SOQL 查询限制
评论
支持 Markdown