411 REFERENCE · Wikibooks
Java Persistence/JPQL BNF
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
JPQL BNF
The following defines the structure of the JPQL query language. For further examples and usage see Querying.
| = or
[] = optional
* = repeatable (zero or more times)
{} = mandatory
QL_statement ::= select_statement | update_statement | delete_statement
Select
Select employee from Employee employee join employee.address address
where address.city = :city and employee.firstName like :name order by employee.firstName
select_statement ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]
From
FROM Employee employee JOIN FETCH employee.address
LEFT OUTER JOIN FETCH employee.phones JOIN employee.manager manager, Employee ceo
from_clause ::= FROM identification_variable_declaration {, {identification_variable_declaration | collection_member_declaration}}*
identification_variable_declaration ::= range_variable_declaration { join | fetch_join }*
range_variable_declaration ::= abstract_schema_name [AS] identification_variable
join ::= join_spec join_association_path_expression [AS] identification_variable
fetch_join ::= join_spec FETCH join_association_path_expression
association_path_expression ::=
collection_valued_path_expression | single_valued_association_path_expression
join_spec::= [ LEFT [OUTER] | INNER ] JOIN
join_association_path_expression ::= join_collection_valued_path_expression |
join_single_valued_association_path_expression
join_collection_valued_path_expression::=
identification_variable.collection_valued_association_field
join_single_valued_association_path_expression::=
identification_variable.single_valued_association_field
collection_member_declaration ::=
IN (collection_valued_path_expression) [AS] identification_variable
single_valued_path_expression ::=
state_field_path_expression | single_valued_association_path_expression
state_field_path_expression ::=
{identification_variable | single_valued_association_path_expression}.state_field
single_valued_association_path_expression ::=
identification_variable.{single_valued_association_field.}* single_valued_association_field
collection_valued_path_expression ::=
identification_variable.{single_valued_association_field.}*collection_valued_association_field
state_field ::= {embedded_class_state_field.}*simple_state_field
Select Clause
SELECT employee.id, employee.phones
SELECT DISTINCT employee.address.city, NEW com.acme.EmployeeInfo(AVG(employee.salary), MAX(employee.salary))
select_clause ::= SELECT [DISTINCT] select_expression {, select_expression}*
select_expression ::=
single_valued_path_expression |
aggregate_expression |
identification_variable |
OBJECT(identification_variable) |
constructor_expression
constructor_expression ::=
NEW constructor_name ( constructor_item {, constructor_item}* )
constructor_item ::= single_valued_path_expression | aggregate_expression
aggregate_expression ::=
{ AVG | MAX | MIN | SUM } ([DISTINCT] state_field_path_expression) |
COUNT ([DISTINCT] identification_variable | state_field_path_expression |
single_valued_association_path_expression)
Where
WHERE employee.firstName = :name AND employee.address.city LIKE 'Ott%' ESCAPE '/'
OR employee.id IN (1, 2, 3) AND (employee.salary * 2) > 40000
where_clause ::= WHERE conditional_expression
conditional_expression ::= conditional_term | conditional_expression OR conditional_term
conditional_term ::= conditional_factor | conditional_term AND conditional_factor
conditional_factor ::= [ NOT ] conditional_primary
conditional_primary ::= simple_cond_expression | (conditional_expression)
simple_cond_expression ::=
comparison_expression |
between_expression |
like_expression |
in_expression |
null_comparison_expression |
empty_collection_comparison_expression |
collection_member_expression |
exists_expression
between_expression ::=
arithmetic_expression [NOT] BETWEEN
arithmetic_expression AND arithmetic_expression |
string_expression [NOT] BETWEEN string_expression AND string_expression |
datetime_expression [NOT] BETWEEN
datetime_expression AND datetime_expression
in_expression ::=
state_field_path_expression [NOT] IN ( in_item {, in_item}* | subquery)
in_item ::= literal | input_parameter
like_expression ::=
string_expression [NOT] LIKE pattern_value [ESCAPE escape_character]
null_comparison_expression ::=
{single_valued_path_expression | input_parameter} IS [NOT] NULL
empty_collection_comparison_expression ::=
collection_valued_path_expression IS [NOT] EMPTY
collection_member_expression ::= entity_expression
[NOT] MEMBER [OF] collection_valued_path_expression
exists_expression::= [NOT] EXISTS (subquery)
all_or_any_expression ::= { ALL | ANY | SOME} (subquery)
comparison_expression ::=
string_expression comparison_operator {string_expression | all_or_any_expression} |
boolean_expression { =|<>} {boolean_expression | all_or_any_expression} |
enum_expression { =|<>} {enum_expression | all_or_any_expression} |
datetime_expression comparison_operator
{datetime_expression | all_or_any_expression} |
entity_expression { = | <> } {entity_expression | all_or_any_expression} |
arithmetic_expression comparison_operator
{arithmetic_expression | all_or_any_expression}
comparison_operator ::= = | > | >= | < | <= | <>
arithmetic_expression ::= simple_arithmetic_expression | (subquery)
simple_arithmetic_expression ::=
arithmetic_term | simple_arithmetic_expression { + | - } arithmetic_term
arithmetic_term ::= arithmetic_factor | arithmetic_term { * | / } arithmetic_factor
arithmetic_factor ::= [{ + | - }] arithmetic_primary
arithmetic_primary ::=
state_field_path_expression |
numeric_literal |
(simple_arithmetic_expression) |
input_parameter |
functions_returning_numerics |
aggregate_expression
string_expression ::= string_primary | (subquery)
string_primary ::=
state_field_path_expression |
string_literal |
input_parameter |
functions_returning_strings |
aggregate_expression
datetime_expression ::= datetime_primary | (subquery)
datetime_primary ::=
state_field_path_expression |
input_parameter |
functions_returning_datetime |
aggregate_expression
boolean_expression ::= boolean_primary | (subquery)
boolean_primary ::=
state_field_path_expression |
boolean_literal |
input_parameter |
enum_expression ::= enum_primary | (subquery)
enum_primary ::=
state_field_path_expression |
enum_literal |
input_parameter |
entity_expression ::=
single_valued_association_path_expression | simple_entity_expression
simple_entity_expression ::=
identification_variable |
input_parameter
Functions
LENGTH(SUBSTRING(UPPER(CONCAT('FOO', :bar)), 1, 5))
functions_returning_numerics::=
LENGTH(string_primary) |
LOCATE(string_primary, string_primary[, simple_arithmetic_expression]) |
ABS(simple_arithmetic_expression) |
SQRT(simple_arithmetic_expression) |
MOD(simple_arithmetic_expression, simple_arithmetic_expression) |
SIZE(collection_valued_path_expression)
functions_returning_datetime ::=
CURRENT_DATE|
CURRENT_TIME |
CURRENT_TIMESTAMP
functions_returning_strings ::=
CONCAT(string_primary, string_primary) |
SUBSTRING(string_primary,
simple_arithmetic_expression, simple_arithmetic_expression)|
TRIM([[trim_specification] [trim_character] FROM] string_primary) |
LOWER(string_primary) |
UPPER(string_primary)
trim_specification ::= LEADING | TRAILING | BOTH
Group By
GROUP BY employee.address.country, employee.address.city HAVING COUNT(employee.id) > 500
groupby_clause ::= GROUP BY groupby_item {, groupby_item}*
groupby_item ::= single_valued_path_expression | identification_variable
having_clause ::= HAVING conditional_expression
Order By
ORDER BY employee.address.country, employee.address.city DESC
orderby_clause ::= ORDER BY orderby_item {, orderby_item}*
orderby_item ::= state_field_path_expression [ ASC | DESC ]
Subquery
WHERE employee.salary = (SELECT MAX(wellPaid.salary) FROM Employee wellPaid)
subquery ::= simple_select_clause subquery_from_clause [where_clause]
[groupby_clause] [having_clause]
subquery_from_clause ::=
FROM subselect_identification_variable_declaration
{, subselect_identification_variable_declaration}*
subselect_identification_variable_declaration ::=
identification_variable_declaration |
association_path_expression [AS] identification_variable |
collection_member_declaration
simple_select_clause ::= SELECT [DISTINCT] simple_select_expression
simple_select_expression::=
single_valued_path_expression |
aggregate_expression |
identification_variable
Update
UPDATE Employee e SET e.salary = e.salary * 2 WHERE e.address.city = :city
update_statement ::= update_clause [where_clause]
update_clause ::= UPDATE abstract_schema_name [[AS] identification_variable]
SET update_item {, update_item}*
update_item ::= [identification_variable.]{state_field | single_valued_association_field} =
new_value
new_value ::=
simple_arithmetic_expression |
string_primary |
datetime_primary |
boolean_primary |
enum_primary |
simple_entity_expression |
NULL
Delete
DELETE FROM Employee e WHERE e.address.city = :city
delete_statement ::= delete_clause [where_clause]
delete_clause ::= DELETE FROM abstract_schema_name [[AS] identification_variable]
Literals
It is normally best to define data values in a query using parameters, using the syntax :parameter or ?.
JPQL also allows for data values to be in-lined in the JPQL query using literals.
JPQL defines the following syntax for literals:
String - 'string' - "Select e from Employee e where e.name = 'Bob'"
To define a ' (quote) character in a string, the quote is double quoted, i.e. 'Baie-D''Urfé'.
Integer - digits - "Select e from Employee e where e.id = 1234"
Long - +|-digitsL - "Select e from Employee e where e.id = 1234L"
Float - +|-digits.decimaleexponentF - "Select s from Stat s where s.ratio > 3.14F"
Double - +|-digits.decimaleexponentD - "Select s from Stat s where s.ratio > 3.14e32D"
Boolean - TRUE | FALSE - "Select e from Employee e where e.active = TRUE"
Date - {d'yyyy-mm-dd'} - "Select e from Employee e where e.startDate = {d'2012-01-03'}"
Time - {t'hh:mm:ss'} - "Select e from Employee e where e.startTime = {t'09:00:00'}"
Timestamp - {ts'yyy-mm-dd hh:mm:ss.nnnnnnnnn'} - "Select e from Employee e where e.version = {ts'2012-01-03 09:00:00.000000001'}"
Enum - package.class.enum - "Select e from Employee e where e.gender = org.acme.Gender.MALE"
null - NULL - "Update Employee e set e.manager = NULL where e.manager = :manager"
New in JPA 2.0
The following new syntax was added in JPA 2.0.
type_discriminator ::= TYPE(identification_variable | single_valued_object_path_expression | input_parameter)
Allows type/class of object to be queried.
SELECT p from Project p where TYPE(p) in (LargeProject, SmallProject)
qualified_identification_variable ::= KEY(identification_variable) | VALUE(identification_variable) | ENTRY(identification_variable)
Allows selecting on Map keys, values and Map Entry.
SELECT ENTRY(e.contactInfo) from Employee e
general_identification_variable ::= identification_variable | KEY(identification_variable) | VALUE(identification_variable)
Allows querying on Map keys and values.
SELECT e from Employee e join e.contactInfo c where KEY(c) = 'Email' and VALUE(c) = 'joe@gmail.com'
in_item ::= literal | single_valued_input_parameter
Allows collection parameters for IN.
SELECT e from Employee e where e.id in :param
functions_returning_strings ::= CONCAT(string_primary, string_primary {, string_primary}*)
Allows CONCAT with multiple arguments.
SELECT e from Employee e where CONCAT(e.address.street, e.address.city, e.address.province) = :address
SUBSTRING(string_primary, simple_arithmetic_expression [, simple_arithmetic_expression])
Allows SUBSTRING with single argument.
SELECT e from Employee e where SUBSTRING(e.name, 3) = 'Mac'
case_expression ::= general_case_expression | simple_case_expression |coalesce_expression | nullif_expression
general_case_expression::= CASE when_clause {when_clause}* ELSE scalar_expression END
when_clause::= WHEN conditional_expression THEN scalar_expression
simple_case_expression::= CASE case_operand simple_when_clause {simple_when_clause}* ELSE scalar_expression END
case_operand::= state_field_path_expression | type_discriminator
simple_when_clause::= WHEN scalar_expression THEN scalar_expression
coalesce_expression::= COALESCE(scalar_expression {, scalar_expression}+)
nullif_expression::= NULLIF(scalar_expression, scalar_expression)
Allows CASE, COALESCE and NULLIF functions.
SELECT e.name, CASE WHEN (e.salary >= 100000) THEN 1 WHEN (e.salary < 100000) THEN 2 ELSE 0 END from Employee e
functions_returning_numerics::= ... | INDEX(identification_variable)
Allows querying in indexed List mapping's index.
SELECT e from Employee e join e.phones p where INDEX(p) = 1 and p.areaCode = '613'
join_collection_valued_path_expression::= identification_variable. {single_valued_embeddable_object_field.}* collection_valued_field
join_single_valued_path_expression::= variable.{single_valued_embeddable_object_field.}*single_valued_object_field
Allows nested dot notation on joins.
SELECT p from Employee e join e.employeeDetails.phones p where e.id = :id
select_item ::= select_expression [[AS] result_variable]
Allows AS option in select.
SELECT AVG(e.salary) AS s, e.address.city from Employee e group by e.address.city order by s
literalTemporal = DATE_LITERAL | TIME_LITERAL | TIMESTAMP_LITERAL
Allows JDBC date/time escape syntax.
SELECT e from Employee e where e.startDate > {d'1990-01-01'}