mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
359 lines
7.2 KiB
Markdown
359 lines
7.2 KiB
Markdown
|
|
<!-- Parent: platform-soql-query/SKILL.md -->
|
||
|
|
# Salesforce CLI SOQL Commands
|
||
|
|
|
||
|
|
## Quick Reference
|
||
|
|
|
||
|
|
| Task | Command |
|
||
|
|
|------|---------|
|
||
|
|
| Run query | `sf data query --query "SELECT..."` |
|
||
|
|
| JSON output | `sf data query --query "..." --json` |
|
||
|
|
| CSV output | `sf data query --query "..." --result-format csv` |
|
||
|
|
| Bulk export | `sf data export bulk --query "SELECT..." --target-org alias` |
|
||
|
|
| Query plan | `sf api request rest '/query/?explain=<SOQL>' --target-org alias` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Basic Queries
|
||
|
|
|
||
|
|
### Run a Query
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Industry FROM Account LIMIT 10" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### Query with Filters
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account WHERE Industry = 'Technology'" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### Query Relationships
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Child-to-parent
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Account.Name FROM Contact LIMIT 10" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
|
||
|
|
# Parent-to-child
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account LIMIT 5" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Output Formats
|
||
|
|
|
||
|
|
### Human-Readable (Default)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account LIMIT 5" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### JSON
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account LIMIT 5" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--json
|
||
|
|
```
|
||
|
|
|
||
|
|
### CSV
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Industry FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--result-format csv > accounts.csv
|
||
|
|
```
|
||
|
|
|
||
|
|
### Direct to File
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Industry FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--result-format csv \
|
||
|
|
--output-file accounts.csv
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Bulk Data Export
|
||
|
|
|
||
|
|
For large result sets (> 2,000 records), use the dedicated bulk export command:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Export to CSV (default)
|
||
|
|
sf data export bulk \
|
||
|
|
--query "SELECT Id, Name FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--output-file accounts.csv
|
||
|
|
|
||
|
|
# Export as JSON
|
||
|
|
sf data export bulk \
|
||
|
|
--query "SELECT Id, Name FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--output-file accounts.json \
|
||
|
|
--result-format json
|
||
|
|
```
|
||
|
|
|
||
|
|
> **Note**: `--bulk` and `--wait` flags on `sf data query` were removed in v2.87.7. Use `sf data export bulk` instead.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Query Plan Analysis
|
||
|
|
|
||
|
|
Analyze query performance before running:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id FROM Account WHERE Name = 'Acme'" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--use-tooling-api \
|
||
|
|
--plan
|
||
|
|
```
|
||
|
|
|
||
|
|
### Understanding Query Plan Output
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"plans": [{
|
||
|
|
"cardinality": 50, // Estimated rows returned
|
||
|
|
"fields": ["Name"], // Fields used for filtering
|
||
|
|
"leadingOperationType": "Index", // Index = good, TableScan = bad
|
||
|
|
"relativeCost": 0.1, // Lower is better
|
||
|
|
"sobjectCardinality": 10000, // Total records in object
|
||
|
|
"sobjectType": "Account"
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Key Indicators:**
|
||
|
|
- `leadingOperationType: "Index"` = Query uses index (good)
|
||
|
|
- `leadingOperationType: "TableScan"` = Full table scan (bad for large tables)
|
||
|
|
- `relativeCost < 1` = Efficient query
|
||
|
|
- `cardinality` = Expected number of results
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Tooling API Queries
|
||
|
|
|
||
|
|
Query metadata objects:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Query ApexClass
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Body FROM ApexClass WHERE Name = 'MyController'" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--use-tooling-api
|
||
|
|
|
||
|
|
# Query CustomField
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, DeveloperName, TableEnumOrId FROM CustomField WHERE TableEnumOrId = 'Account'" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--use-tooling-api
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Query from File
|
||
|
|
|
||
|
|
Store query in file and execute:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create query file
|
||
|
|
echo "SELECT Id, Name FROM Account WHERE Industry = 'Technology'" > query.soql
|
||
|
|
|
||
|
|
# Execute from file
|
||
|
|
sf data query \
|
||
|
|
--file query.soql \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Useful Patterns
|
||
|
|
|
||
|
|
### Get Record Count
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT COUNT() FROM Account" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### Export to File
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# CSV export
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Industry, Phone FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--result-format csv > accounts.csv
|
||
|
|
|
||
|
|
# JSON export
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Industry FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--json > accounts.json
|
||
|
|
```
|
||
|
|
|
||
|
|
### Query with jq Processing
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Get just the names
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Name FROM Account LIMIT 10" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--json | jq -r '.result.records[].Name'
|
||
|
|
|
||
|
|
# Count records
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--json | jq '.result.totalSize'
|
||
|
|
|
||
|
|
# Filter in shell
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name, Industry FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--json | jq '.result.records[] | select(.Industry == "Technology")'
|
||
|
|
```
|
||
|
|
|
||
|
|
### Query with Dates
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Records created today
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account WHERE CreatedDate = TODAY" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
|
||
|
|
# Records from last 30 days
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account WHERE CreatedDate = LAST_N_DAYS:30" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### Aggregate Queries
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Count by industry
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Industry, COUNT(Id) FROM Account GROUP BY Industry" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
|
||
|
|
# Sum of amounts
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT SUM(Amount) FROM Opportunity WHERE StageName = 'Closed Won'" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Query Timeout
|
||
|
|
|
||
|
|
For long-running queries, export via bulk API:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data export bulk \
|
||
|
|
--query "SELECT Id, Name FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--output-file results.csv
|
||
|
|
```
|
||
|
|
|
||
|
|
### Too Many Results
|
||
|
|
|
||
|
|
Add LIMIT or filter:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# With limit
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account LIMIT 1000" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
|
||
|
|
# With filter
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account WHERE CreatedDate = THIS_YEAR" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### Non-Selective Query Error
|
||
|
|
|
||
|
|
Add indexed field to WHERE:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Add CreatedDate filter (indexed)
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id FROM Lead WHERE Status = 'Open' AND CreatedDate = LAST_N_DAYS:90" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
### Permission Errors
|
||
|
|
|
||
|
|
Check field-level security:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Query accessible fields only
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account" \
|
||
|
|
--target-org my-sandbox
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Integration with Other Tools
|
||
|
|
|
||
|
|
### Pipe to File
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Id, Name FROM Account" \
|
||
|
|
--target-org my-sandbox \
|
||
|
|
--result-format csv | tee accounts.csv
|
||
|
|
```
|
||
|
|
|
||
|
|
### Use in Scripts
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
|
||
|
|
ORG=${1:-"my-sandbox"}
|
||
|
|
|
||
|
|
# Get count
|
||
|
|
COUNT=$(sf data query \
|
||
|
|
--query "SELECT COUNT() FROM Account" \
|
||
|
|
--target-org $ORG \
|
||
|
|
--json | jq -r '.result.totalSize')
|
||
|
|
|
||
|
|
echo "Total accounts: $COUNT"
|
||
|
|
|
||
|
|
# Get top accounts
|
||
|
|
sf data query \
|
||
|
|
--query "SELECT Name, AnnualRevenue FROM Account ORDER BY AnnualRevenue DESC LIMIT 10" \
|
||
|
|
--target-org $ORG
|
||
|
|
```
|
||
|
|
|
||
|
|
### Compare Orgs
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
|
||
|
|
PROD_COUNT=$(sf data query --query "SELECT COUNT() FROM Account" --target-org prod --json | jq '.result.totalSize')
|
||
|
|
SANDBOX_COUNT=$(sf data query --query "SELECT COUNT() FROM Account" --target-org sandbox --json | jq '.result.totalSize')
|
||
|
|
|
||
|
|
echo "Production accounts: $PROD_COUNT"
|
||
|
|
echo "Sandbox accounts: $SANDBOX_COUNT"
|
||
|
|
echo "Difference: $((PROD_COUNT - SANDBOX_COUNT))"
|
||
|
|
```
|