Feed query language
On this page
A feed’s records come from a query: a base object plus four optional clauses. The clauses use SQL syntax but are not SQL. They are parsed, checked against the fields that actually exist, and rebuilt before they reach the database, so nothing written here is passed through as a SQL string.
| Part | Field on Query | Purpose |
|---|---|---|
| Object | s_c__Object_API_Name__c |
The base object to select from, as a Salesforce API name such as product2 or s_c__article__c |
from |
s_c__From__c |
Declares related objects to join, each with an alias and a match condition |
where |
s_c__Where__c |
Filters which records are returned |
order |
s_c__Order__c |
Orders them |
select |
s_c__Select__c |
Optional. Projects a specific set of columns instead of whole records |
A query with only an object returns every record of that object.
Each part is a separate field on the Query record (s_c__Query__c), not one statement typed in one place. A field holds its clause body without the leading keyword, so Where holds s_c__active__c = true, not WHERE s_c__active__c = true. From is the exception: it holds the join clauses themselves, each beginning with JOIN, INNER JOIN or LEFT JOIN. Every example below is the contents of one field.
Naming fields
Refer to a field by its Salesforce API name in full, including prefixes and suffixes: s_c__slug__c, name, createddate. Shortened or Ruby-style names are not accepted.
An unqualified name is a field on the base object. A qualified name such as brand.name is a field on a join, where brand is an alias declared in from. Keywords like AND and JOIN are case-insensitive.
An unknown object, unknown field or undeclared alias is rejected loudly. A query is never quietly reduced to an empty result because of a typo.
where
| Operator | Meaning |
|---|---|
= != > >= < <= |
Comparisons |
BETWEEN x AND y |
Inclusive range |
IN (a, b) / NOT IN (a, b) |
Membership |
LIKE 'pattern' / NOT LIKE 'pattern' |
Pattern match, case-sensitive |
ILIKE 'pattern' / NOT ILIKE 'pattern' |
Pattern match, case-insensitive |
IS NULL / IS NOT NULL |
Null checks |
Combine with AND, OR, NOT and parentheses. Values are single-quoted strings (doubling a quote to escape it), numbers, true or false, and NULL.
```sql
s_c__is_master__c = true AND s_c__active__c = true
s_c__price__c BETWEEN 10 AND 50 AND brand.name LIKE ‘Ac%’
type = ‘physical’ AND (s_c__category__c IN (‘sale’, ‘clearance’) OR s_c__featured__c = true) ```
:::warning
A negated comparison does not match null. !=, NOT IN and NOT LIKE leave out rows where the field is empty, which is rarely what the author intended. Add IS NULL explicitly when those rows should be included.
:::
Matching regardless of case
Every comparison is case-sensitive by default, so name = 'Red' does not match red.
For pattern matching, use ILIKE instead of LIKE. For everything else, wrap both operands in LOWER() or UPPER():
```sql
LOWER(s_c__brand__c) = LOWER(‘Acme’)
LOWER(s_c__category__c) IN (LOWER(‘Sale’), LOWER(‘Clearance’)) ```
Folding one side only leaves the other side’s case intact and still fails to match, which is the usual mistake. LOWER and UPPER need a text column and are rejected on a number, date or boolean.
from
```sql
[INNER | LEFT] JOIN
Joins default to INNER. Use LEFT to keep base rows with no match, such as a product with no brand. The ON is a match key only, written out in full, and joins on equality; it is not a second filter. An unqualified column in the ON is on the base object.
Several joins are allowed, and a later one may reference an earlier alias to form a chain, which is how a junction object is traversed:
```sql
JOIN account AS brand ON s_c__brand_id__c = brand.sfid
JOIN s_c__products_product_categories__c AS pc ON sfid = pc.s_c__product_id__c JOIN s_c__product_category__c AS cat ON pc.s_c__category_id__c = cat.sfid ```
Aliases must be unique and must not share a name with a base-object field.
To-one and to-many joins behave differently
Which one a join is comes from the ON: the side whose matched column is that table’s own sfid is the “one” side.
- To-one (
base.<foreign key> = alias.sfid) matches at most one related row, and can be used in bothwhereandorder. - To-many (
base.sfid = alias.<foreign key>) may match many. It can filter inwhere, compiled as an existence check so base rows are never duplicated, but ordering by it is rejected, because ordering by a one-to-many relationship has no defined answer.
order
```sql
Was this article helpful?
Thanks for your feedback! It helps us improve our docs.