Skip to main content

Syntax & Grammar

A FOQL query is a single select statement. It always begins with a select list and a from module, followed by optional where, group by, order by, limit, and offset clauses — in that order.

Grammar specification (EBNF)#

The following EBNF describes the accepted FOQL grammar. Terminals are shown in "quotes"; { ... } means zero or more; [ ... ] means optional; | is alternation.

query           ::= select_clause                    from_clause                    [ where_clause ]                    [ group_by_clause ]                    [ order_by_clause ]                    [ limit_clause ]                    [ offset_clause ] ;
select_clause   ::= "select" select_list ;select_list     ::= select_item { "," select_item } ;select_item     ::= ( field_path | aggregate ) [ "as" alias ] ;aggregate       ::= agg_func "(" field_path ")" ;agg_func        ::= "sum" | "avg" | "min" | "max" | "count" ;
from_clause     ::= "from" module_name ;
where_clause    ::= "where" condition ;condition       ::= predicate                  | "(" condition ")"                  | condition "and" condition                  | condition "or" condition ;predicate       ::= field_path operator value                  | field_path "is" [ "not" ] "null"                  | field_path [ "not" ] "in" "(" value_list ")"                  | field_path [ "not" ] "between" value "and" value                  | field_path [ "not" ] "like" string_literal ;operator        ::= "=" | "!=" | ">" | ">=" | "<" | "<=" ;
group_by_clause ::= "group" "by" field_path { "," field_path } ;order_by_clause ::= "order" "by" order_item { "," order_item } ;order_item      ::= ( field_path | alias ) [ "asc" | "desc" ] ;limit_clause    ::= "limit" integer ;offset_clause   ::= "offset" integer ;
field_path      ::= field { "." field } ;   (* dot = lookup traversal *)field           ::= identifier ;module_name     ::= identifier ;alias           ::= identifier ;value           ::= string_literal | number | boolean | "null" ;value_list      ::= value { "," value } ;string_literal  ::= "'" { character } "'" ;boolean         ::= "true" | "false" ;identifier      ::= letter { letter | digit | "_" } ;

Annotated reference query#

This query exercises most of the language at once — scalar fields, an aggregate, lookup traversals, an alias, filtering, grouping, multi-field ordering, and pagination:

select id,       sum(totalCost),       serialNumber,       subject,       status,       multi_enum_field_workorder as enumLabels,       multi_lookup_field_workorder,       priority,       priority.displayName,       vendor,       vendor.name,       lookup_workorder_1,       vendor.moduleState,       vendor.moduleState.displayNamefrom workorderwhere priority = 'Low'group by category, statusorder by createdTime desc, id asclimit 100 offset 0
TokenMeaning
idA scalar field of workorder.
sum(totalCost)Aggregate function over the totalCost field.
serialNumber, subjectScalar fields.
statusA lookup field; returns the related state id as a flat value unless traversed.
multi_enum_field_workorder as enumLabelsA multi-enum field, returned under the alias enumLabels.
multi_lookup_field_workorderA multi-lookup field (returns a list of related record ids).
priorityA lookup field; by itself returns the related record id as a flat value.
priority.displayNameTraversal: the displayName field of the priority lookup's target module.
vendor / vendor.namevendor returns a flat id ("vendor": 88); vendor.name pulls name from the vendor module.
lookup_workorder_1A custom lookup field on workorder.
vendor.moduleState.displayNameTwo-hop traversal: vendor → its moduleState (status) → that state's displayName.
from workorderBase module.
where priority = 'Low'Filter.
group by category, statusGrouping (required when aggregates are mixed with scalar columns).
order by createdTime desc, id ascMulti-field sort.
limit 100 offset 0Pagination.
tip

For the meaning of each clause in depth, see Clauses. For how dotted lookups like vendor.moduleState.displayName resolve, see Lookup Traversal.