> For the complete documentation index, see [llms.txt](https://docs.appstrategy.com/apprules-r-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appstrategy.com/apprules-r-documentation/platform/platform-features/system-settings/data-sources/sql-compliance/crm/salesforce.md).

# Salesforce

```sql
SELECT Name, AnnualRevenue FROM Account
SELECT * FROM Account
SELECT Name AS CompanyName FROM Account
SELECT Owner.Name, Name FROM Account
```

Relationship fields are supported in the `SELECT` list and are returned flattened onto the column name.

#### WHERE

Operators: `=`, `<>`, `!=`, `<`, `<=`, `>`, `>=`, `LIKE`, `NOT LIKE`, `IN`, `NOT IN`, `IS NULL`, `IS NOT NULL`. Combine with `AND` / `OR` and parentheses. Parameters are supported (`@name`).

```sql
SELECT Name FROM Account WHERE Industry = 'Technology' AND Name LIKE 'Acme%'
SELECT Name FROM Opportunity WHERE StageName IN ('Prospecting', 'Qualification')
SELECT Name FROM Account WHERE ParentId IS NOT NULL
```

The whole `WHERE` clause is translated into the SOQL query and evaluated by Salesforce.

#### ORDER BY, LIMIT, OFFSET

```sql
SELECT Name FROM Account ORDER BY Name DESC
SELECT Name FROM Account ORDER BY CreatedDate DESC LIMIT 50 OFFSET 100
```

#### Aggregate functions

| Function                 | Example                                                               |
| ------------------------ | --------------------------------------------------------------------- |
| `COUNT(*)`               | `SELECT COUNT(*) FROM Account WHERE Name = 'MyAccount'`               |
| `COUNT(column)`          | `SELECT COUNT(ParentId) FROM Account`                                 |
| `COUNT(DISTINCT column)` | `SELECT COUNT(DISTINCT AccountId) AS DistinctValues FROM Opportunity` |
| `AVG`                    | `SELECT AccountId, AVG(Amount) FROM Opportunity GROUP BY AccountId`   |
| `MIN`                    | `SELECT MIN(Amount), AccountId FROM Opportunity GROUP BY AccountId`   |
| `MAX`                    | `SELECT AccountId, MAX(Amount) FROM Opportunity GROUP BY AccountId`   |
| `SUM`                    | `SELECT SUM(Amount) FROM Opportunity WHERE StageName = 'Closed Won'`  |

`GROUP BY` and `HAVING` are supported, and `ORDER BY` / `LIMIT` / `OFFSET` apply to the grouped result:

```sql
SELECT StageName, COUNT(*) AS Total, SUM(Amount) AS Pipeline
  FROM Opportunity
 WHERE IsClosed = false
 GROUP BY StageName
HAVING COUNT(*) > 5
 ORDER BY Pipeline DESC
```

**How it runs.** Unlike the other CRM connectors, nothing is aggregated locally. SOQL has real aggregate functions, `GROUP BY` and `HAVING`, so the statement is pushed down whole and Salesforce computes the result. Two translations are worth knowing about:

* `COUNT(DISTINCT field)` becomes SOQL's `COUNT_DISTINCT(field)`. SOQL has no `DISTINCT` form of `SUM`, `AVG`, `MIN` or `MAX`, so those are rejected.
* `COUNT(*)` becomes `COUNT(Id)`. SOQL's bare `COUNT()` returns no records at all, only a total, and is rejected outright inside a `GROUP BY` query.

Salesforce returns aggregated expressions under generated aliases (`expr0`, `expr1`, …); the connector maps those back onto the names you asked for, so the result set carries your alias, or the call as written when there is no alias.

`COUNT(*)` counts rows. Every other aggregate ignores nulls.

#### JOIN

Inner joins and left outer joins across two or more objects, in either syntax:

```sql
SELECT Account.Name, Contact.FirstName, Contact.LastName
  FROM Account, Contact
 WHERE Account.Id = Contact.AccountId

SELECT a.Name, c.FirstName
  FROM Account a LEFT OUTER JOIN Contact c ON a.Id = c.AccountId
```

SOQL has no join between unrelated objects, so joins are executed by the connector as a hash join over the rows each side returns. Each side's own `WHERE` conditions are translated into its SOQL query before the join.

#### INSERT, UPDATE, DELETE

```sql
INSERT INTO Account (Name, AnnualRevenue) VALUES ('Acme', 500000)
UPDATE Account SET AnnualRevenue = 600000 WHERE Id = '001...'
DELETE FROM Account WHERE Id = '001...'
```

#### Not supported

* `SELECT DISTINCT` — accepted by the parser but **ignored**; use `GROUP BY` on the same columns instead.
* `BETWEEN` — write `>= x AND <= y`.
* `RIGHT`, `FULL` and `CROSS` joins.
* Aggregates combined with joins in one statement.
* `SELECT *` combined with `GROUP BY` or an aggregate — list the grouped columns.
* `SUM`, `AVG`, `MIN`, `MAX` with `DISTINCT` — SOQL has no such form.
* Subqueries, `UNION`, and expressions or scalar functions in the `SELECT` list.

A column that is neither aggregated nor listed in `GROUP BY` is rejected by the connector, naming the offending column — Salesforce's own error for this does not.

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.appstrategy.com/apprules-r-documentation/platform/platform-features/system-settings/data-sources/sql-compliance/crm/salesforce.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
