
The following BNF notation (Backus Naur Form) specifies the syntax rules of SOQL. Use it to debug syntax errors or more fully understand what syntax is valid in SOQL.
QUERY ::= 'SELECT' ('COUNT()' | (FIELD ( ',' FIELD)*))
'FROM' UNQUALIFIEDNAME ('AS' ? UNQUALIFIEDNAME)? ('USING' UNQUALIFIEDNAME)?
(PARENT_ALIAS_EXPR)*
('WHERE' CONDITIONEXPR )?
('ORDER BY' ORDERBYEXPR)?
('LIMIT' POSINTEGER )?
FIELD ::= NAME | 'toLabel' '(' NAME ')' | '(' QUERY ')'
PARENT_ALIAS_EXPR ::= ',' QUALIFIEDNAME ('AS' ? UNQUALIFIEDNAME)?
('USING' UNQUALIFIEDNAME)?
CONDITIONEXPR ::= ANDEXPR | OREXPR | NOTEXPR | SIMPLEEXPR
ANDEXPR ::= SIMPLEEXPR 'AND' SIMPLEEXPR ('AND' SIMPLEEXPR)*
OREXPR ::= SIMPLEEXPR 'OR' SIMPLEEXPR ('OR' SIMPLEEXPR)*
NOTEXPR ::= 'NOT' SIMPLEEXPR
SIMPLEEXPR ::= '(' CONDITIONEXPR ')' | FIELDEXPR | SETEXPR
FIELDEXPR ::= NAME OPERATOR VALUE | NAME MATHOPERATOR NAME OPERATOR VALUE
SETEXPR ::= NAME ('includes' | 'excludes' | 'in' | 'not' 'in') '(' VALUE
(',' VALUE)* ')'
ORDERBYEXPR ::= NAME ('asc' | 'desc')? ('nulls' ('first'|'last'))?
(',' NAME ('asc' | 'desc')? ('nulls' ('first'|'last'))?)*
OPERATOR ::= '=' | '!=' | '<' | '<=' | '>' | '>=' | 'like'
MATHOPERATOR ::= '+' | '-'
VALUE ::= STRING_LITERAL | NUMBER | DATE | DATETIME | NULL | TRUE | FALSE |
DATEFORMULA | CURRENCY
DATEFORMULA ::= YESTERDAY | TODAY | TOMORROW | LAST_WEEK | THIS_WEEK |
NEXT_WEEK | THIS_MONTH | LAST_MONTH | NEXT_MONTH | LAST_90_DAYS |
NEXT_90_DAYS | LAST_N_DAYS ':' INTEGER | NEXT_N_DAYS ':' INTEGER |
THIS_QUERTER | LAST_QUARTER | NEXT_QUARTER | NEXT_N_QUARTERS ':'
INTEGER | LAST_N_QUARTERS ':' INTEGER | THIS_YEAR | LAST_YEAR |
NEXT_YEAR | THIS_FISCAL_QUARTER | NEXT_N_YEARS ':' INTEGER |
LAST_N_YEARS ':' INTEGER | LAST_FISCAL_QUARTER | NEXT_FISCAL_QUARTER |
NEXT_N_FISCAL_QUARTERS ':' INTEGER | LAST_N_FISCAL_QUARTERS ':' INTEGER |
THIS_FISCAL_YEAR | LAST_FISCAL_YEAR | NEXT_FISCAL_YEAR |
NEXT_N_FISCAL_YEARS ':' INTEGER | LAST_N_FISCAL_YEARS ':' INTEGER
UNQUALIFIEDNAME ::= LETTER (NAMECHAR)*
QUALIFIEDNAME ::= UNQUALIFIEDNAME ('.' UNQUALIFIEDNAME)*
NAME ::= QUALIFIEDNAME | UNQUALIFIEDNAME
LETTER ::= 'a'..'z' | 'A'..'Z'
NAMECHAR ::= LETTER | DIGIT | '_'
DATE ::= YEAR '-' MONTH '-' DAY
DATETIME ::= DATE 'T' HOUR ':' MINUTE ':' SECOND ('Z' | (('+' |'-')
TZHOUR ( ':' TZMINUTE)? ))
YEAR ::= DIGIT DIGIT DIGIT DIGIT
MONTH ::= '0' '1'..'9' | '1' ('0' | '1' | '2')
DAY ::= '0' '1'..'9' | '1'..'2' DIGIT | '3' ('0' | '1')
HOUR ::= '0'..'1' DIGIT | '2' '0'..'3'
MINUTE ::= '0'..'5' DIGIT
TZHOUR ::= DIGIT | TZHOUR DIGIT
TZMINUTE ::= DIGIT | TZMINUTE DIGIT
SECOND ::= '0'..'5' DIGIT ( '.' POSINTEGER )?
CURRENCY ::= (LETTER)* NUMBER
NULL ::= 'null'
TRUE ::= 'true'
FALSE ::= 'false'
NUMBER ::= '.' POSINTEGER | INTEGER '.' POSINTEGER
INTEGER ::= ('+' | '-')? POSINTEGER
POSINTEGER ::= DIGIT+
DIGIT ::= '0'..'9'
STRING_LITERAL ::= "'" (ESC_CHAR | ~("'"))* "'"
ESC_CHAR ::= '\' ('n' | 'r' | 't' | '"' | "'" | '\')
WS ::= S+
S ::= ' ' | S ' ' | ''