mcpField
S
sf-soql

sf-soql

github.com/clientell-ai数据与数据库20104 次安装32 周前更新
代码仓库

关于 sf-soql

面向 Salesforce 开发者的 SOQL 查询构建与优化指南,涵盖关系查询、聚合、SOSL 和动态 SOQL。重点强调用户模式安全、绑定变量、选择性筛选及常见限制。

主要功能

  1. 01构建关系与聚合查询
  2. 02使用 SOSL 进行全文搜索
  3. 03采用用户模式和绑定变量
  4. 04识别低效查询模式
  5. 05利用查询计划分析性能
  6. 06检查查询限制与语法注意事项

适用场景

  1. 01编写符合权限控制的 Salesforce 查询
  2. 02搜索多个对象的文本内容
  3. 03优化大型数据集的查询
  4. 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_ENFORCEDUSER_MODE
FLS 强制执行仅 SELECT/FROMSELECT/FROM/WHERE/子查询
发生违规时抛出异常静默移除不可访问的字段
限制规则不支持支持
建议旧版——请迁移首选

优化规则

选择性筛选条件(使用索引字段)
  • Id、Name、OwnerId、CreatedDate、SystemModstamp
  • RecordTypeId、Lookup 字段、External ID 字段
  • 标记为 External ID 或具有自定义索引的自定义字段
要识别的反模式
  1. 循环中执行查询——将查询移到循环之前,使用 Map/Set
  2. 非选择性筛选条件——优先按索引字段筛选
  3. 相当于 SELECT *——绝不要选择所有字段,只选择所需字段
  4. 缺少 LIMIT——对于可能返回大量数据的查询,添加 LIMIT
  5. 否定筛选条件——!= 和 NOT IN 都不是选择性的
  6. 前置通配符——LIKE '%term' 无法使用索引
  7. 缺少 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 一起使用

工作流

  1. 了解数据需求
  2. 检查对象关系和字段类型
  3. 使用正确的筛选条件、安全设置和限制来构建查询
  4. 使用以下命令测试:sf data query -q "YOUR_QUERY" --target-org myOrg
  5. 根据结果和解释计划进行优化

参考资料

  • SOQL/SOSL 参考 — 日期字面量、SOSL 语法、FIELDS()、地理位置、动态 SOQL、聚合、FOR UPDATE、绑定模式、查询计划
  • 治理限制 — 每个事务的 SOQL 查询限制

评论

支持 Markdown