The Java Persistence query language (JPQL) is used to define searches
against persistent entities independent of the mechanism used to
store those entities. As such, JPQL is "portable", and not constrained to
any particular data store. The Java
Persistence query language is an extension of the Enterprise JavaBeans
query language,
EJB QL
, adding operations such
as bulk deletes and updates, join operations, aggregates, projections,
and subqueries. Furthermore, JPQL queries can be declared statically in
metadata, or can be dynamically built in code. This chapter provides the full
definition of the language.
Much of this section is paraphrased or taken directly
from Chapter 4 of the JSR 220 specification.
A JPQL statement
may be either a
SELECT
statement, an
UPDATE
statement, or a
DELETE
statement. This chapter refers to all
such statements as "queries". Where
it is important to distinguish among statement types, the specific
statement type is referenced. In BNF syntax, a query language statement
is defined as:
QL_statement ::= select_statement | update_statement | delete_statement
The Java Persistence query language is a typed language, and every expression has a type. The type of an expression is derived from the structure of the expression, the abstract schema types of the identification variable declarations, the types to which the persistent fields and relationships evaluate, and the types of literals. The abstract schema type of an entity is derived from the entity class and the metadata information provided by Java language annotations or in the XML descriptor. Informally, the abstract schema type of an entity can be characterized as follows: For every persistent field or get accessor method (for a persistent property) of the entity class, there is a field ("state-field") whose abstract schema type corresponds to that of the field or the result type of the accessor method. For every persistent relationship field or get accessor method (for a persistent relationship property) of the entity class, there is a field ("association-field") whose type is the abstract schema type of the related entity (or, if the relationship is a one-to-many or many-to-many, a collection of such). Abstract schema types are specific to the query language data model. The persistence provider is not required to implement or otherwise materialize an abstract schema type. The domain of a query consists of the abstract schema types of all entities that are defined in the same persistence unit. The domain of a query may be restricted by the navigability of the relationships of the entity on which it is based. The association-fields of an entity's abstract schema type determine navigability. Using the association-fields and their values, a query can select related entities and use their abstract schema types in the query.
SELECT DISTINCT mag FROM Magazine AS mag JOIN mag.articles AS art WHERE art.published = FALSEThis query navigates over the association-field authors of the abstract schema type
Magazine
to find articles,
and uses the state-field
published
of
Article
to select those
magazines that have at least one article that is published.
Although predefined reserved identifiers,
such as
DISTINCT
,
FROM
,
AS
,
JOIN
,
WHERE
, and
FALSE
, appear in upper case
in this example, predefined reserved identifiers are case insensitive. The
SELECT
clause of this example designates the return type of this query to
be of type
Magazine
. Because the same persistence unit defines the abstract
persistence schemas of the related entities, the developer can also
specify a query over
articles
that utilizes the abstract
schema type for
products, and hence the state-fields and association-fields of both the
abstract schema types
Magazine
and
Author
. For example, if the abstract
schema type
Author
has a state-field named
firstName
, a query over
articles
can be specified using this state-field. Such a query might be
to find all magazines that have articles authored by someone with the
first name "John".
SELECT DISTINCT mag FROM Magazine mag
JOIN mag.articles art JOIN art.author auth WHERE auth.firstName = 'John'
Because
Magazine
is related to
Author
by means of the relationships between
Magazine
and
Article
and between
Article
and
Author
, navigation using
the association-fields authors and product is used to express the
query. This query is specified by using the abstract schema name
Magazine
,
which designates the abstract schema type over which the query ranges. The
basis for the navigation is provided by the association-fields authors
and product of the abstract schema types
Magazine
and
Article
respectively.
The
FROM
clause of
a query defines the domain of the query by declaring identification
variables. An identification variable is an identifier declared in the
FROM
clause of a query. The domain of the query may be constrained by
path expressions. Identification variables designate instances of a
particular entity abstract schema type. The
FROM
clause can contain
multiple identification variable declarations separated by a comma (,).
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
join_association_path_expression ::= join_collection_valued_path_expression | join_single_valued_association_path_expression
join_spec ::= [ LEFT [OUTER] | INNER ] JOIN
collection_member_declaration ::= IN (collection_valued_path_expression) [AS] identification_variable
SELECT DISTINCT mag FROM Magazine mag JOIN mag.articles art JOIN art.author auth WHERE auth.firstName = 'John'In the
FROM
clause
declaration
mag.articles
art
,
the identification variable
art
evaluates to
any
Article
value directly reachable from
Magazine
. The association-field
articles
is a collection of instances
of the abstract schema type
Article
and the identification variable
art
refers to an element of this
collection. The type of
auth
is the abstract
schema type of
Author
. An
identification variable ranges over the abstract schema type of an
entity. An identification variable designates an instance of an entity
abstract schema type or an element of a collection of entity abstract
schema type instances. Identification variables are existentially
quantified in a query. An identification variable always designates a
reference to a single value. It is declared in one of three ways: in a
range variable declaration, in a join clause, or in a collection member
declaration. The identification variable declarations are evaluated
from left to right in the
FROM
clause, and an identification variable
declaration can use the result of a preceding identification variable
declaration of the query string.
Magazine
,
the path expression
mag.articles.author
is illegal since
navigation to authors results in a collection. This case should produce
an error when the query string is verified. To handle such a navigation,
an identification variable must be declared in the
FROM
clause to range
over the elements of the
articles
collection. Another path expression
must be used to navigate over each such element in the
WHERE
clause of
the query, as in the following query, which returns all authors that have
any articles in any magazines:
SELECT DISTINCT art.author FROM Magazine AS mag, IN(mag.articles) art
An inner join may be implicitly specified by the use of a
cartesian product in the
FROM
clause and a join
condition in the
WHERE
clause.
The syntax for explicit join operations is as follows:
join ::= join_spec join_association_path_expression [AS] identification_variable
fetch_join ::= join_spec FETCH join_association_path_expression
join_association_path_expression ::= join_collection_valued_path_expression | join_single_valued_association_path_expression
join_spec ::= [ LEFT [OUTER] | INNER ] JOIN
SELECT pub FROM Publisher pub JOIN pub.magazines mag WHERE pub.revenue > 1000000The keyword
INNER
may optionally be used:
SELECT pub FROM Publisher pub INNER JOIN pub.magazines mag WHERE pub.revenue > 1000000This is equivalent to the following query using the earlier
IN
construct. It selects those
publishers with revenue of over 1 million for which at least one magazine exists:
SELECT OBJECT(pub) FROM Publisher pub, IN(pub.magazines) mag WHERE pub.revenue > 1000000
LEFT [OUTER] JOIN join_association_path_expression [AS] identification_variableFor example:
SELECT pub FROM Publisher pub LEFT JOIN pub.magazines mag WHERE pub.revenue > 1000000The keyword
OUTER
may optionally be used:
SELECT pub FROM Publisher pub LEFT OUTER JOIN pub.magazines mags WHERE pub.revenue > 1000000An important use case for
LEFT JOIN
is in enabling the prefetching of related data items as
a side effect of a query. This is accomplished by specifying the
LEFT JOIN
as a
FETCH JOIN
.
GROUP BY
construct
enables the aggregation of values according to the properties of an entity
class. The
HAVING
construct enables conditions to be specified that
further restrict the query result as restrictions upon the groups. The
syntax of the
HAVING
clause is as follows:
having_clause ::= HAVING conditional_expression
GROUP BY
and
HAVING
constructs are further discussed in
Section 10.2.6, “JPQL GROUP BY, HAVING”
.
The following sections describe the language
constructs that can be used in a conditional expression of the
WHERE
clause or
HAVING
clause. State-fields that are mapped in serialized form
or as lobs may not be portably used in conditional expressions.
The implementation is not
expected to perform such query operations involving such fields in memory
rather than in the database.
All identification variables used
in the
WHERE
or
HAVING
clause of a
SELECT
or
DELETE
statement must
be declared in the
FROM
clause, as described in
Section 10.2.3.2, “JPQL Identification Variables”
. The
identification variables used in the
WHERE
clause of
an
UPDATE
statement
must be declared in the
UPDATE
clause.
Identification variables are
existentially quantified in the
WHERE
and
HAVING
clause. This means
that an identification variable represents a member of a collection
or an instance of an entity's abstract schema type. An identification
variable never designates a collection in its entirety.
Either positional or named parameters may be
used. Positional and named parameters may not be mixed in a single
query. Input parameters can only be used in the
WHERE
clause or
HAVING
clause of a query.
Note that if an input parameter value is null, comparison operations
or arithmetic operations involving the input parameter will return an
unknown value. See
Section 10.2.10, “JPQL Null Values”
.
A named parameter is an identifier that is prefixed by the ":" symbol. It follows the rules for identifiers defined in Section 10.2.3.1, “JPQL FROM Identifiers” . Named parameters are case sensitive. Example:
SELECT pub FROM Publisher pub WHERE pub.revenue > :rev
HAVING
clause. See
Section 10.2.6, “JPQL GROUP BY, HAVING”
.
x BETWEEN y AND zis semantically equivalent to:
y <= x AND x <= zThe rules for unknown and
NULL
values in comparison operations apply. See
Section 10.2.10, “JPQL Null Values”
. Examples
p.age BETWEEN 15 and 19is equivalent to
p.age >= 15 AND p.age <= 19
p.age NOT BETWEEN 15 and 19is equivalent to
p.age < 15 OR p.age > 19
The syntax for the use of the comparison operator
[
NOT
]
IN
in a conditional expression is as follows:
The state_field_path_expression must have a string, numeric, or enum
value. The literal and/or input_parameter values must be like the same
abstract schema type of the state_field_path_expression in type. (See
Section 10.2.11, “JPQL Equality and Comparison Semantics”
).
The results of the subquery must be like the same abstract schema type
of the state_field_path_expression in type. Subqueries are discussed in
Section 10.2.5.15, “JPQL Subqueries”
. Examples are:
o.country IN ('UK', 'US', 'France')
is true for UK and false for Peru, and is equivalent to the
expression:
(o.country = 'UK') OR (o.country = 'US') OR (o.country = ' France')In the following expression:
o.country NOT IN ('UK', 'US', 'France')
is false for UK and true for Peru, and is equivalent to the expression:
NOT ((o.country = 'UK') OR (o.country = 'US') OR (o.country = 'France'))There must be at least one element in the comma separated list that defines the set of values for the
IN
expression. If the value of a state_field_path_expression in an
IN
or
NOT IN
expression is
NULL
or unknown, the value of the expression is unknown.
address.phone LIKE '12%3'is true for '123' '12993' and false for '1234'
asentence.word LIKE 'l_se'is true for 'lose' and false for 'loose'
aword.underscored LIKE '\_%' ESCAPE '\'is true for '_foo' and false for 'bar'
address.phone NOT LIKE '12%3'is false for '123' and '12993' and true for '1234' If the value of the string_expression or pattern_value is
NULL
or unknown, the value of the
LIKE
expression
is unknown. If the escape_character is specified and is
NULL
, the value
of the
LIKE
expression is unknown.
SELECT mag FROM Magazine mag WHERE mag.articles IS EMPTYIf the value of the collection-valued path expression in an empty collection comparison expression is unknown, the value of the empty comparison expression is unknown.
An
ALL
conditional expression is a predicate
that is true if the comparison operation is true for all values in the
result of the subquery or the result of the subquery is empty. An
ALL
conditional expression is false
if the result of the comparison is false
for at least one row, and is unknown if neither true nor false. An
ANY
conditional expression is a
predicate that is true if the comparison
operation is true for some value in the result of the subquery. An
ANY
conditional expression is false if the
result of the subquery is empty
or if the comparison operation is false for every value in the result
of the subquery, and is unknown if neither true nor false. The keyword
SOME
is synonymous with
ANY
.
The comparison operators used with
ALL
or
ANY
conditional expressions are =, <, <=, >, >=, <>. The result of
the subquery must be like that of the other argument to the comparison
operator in type. See
Section 10.2.11, “JPQL Equality and Comparison Semantics”
.
The syntax of an
ALL
or
ANY
expression is specified as follows:
all_or_any_expression ::= { ALL | ANY | SOME} (subquery)
SELECT auth FROM Author auth
WHERE auth.salary >= ALL(SELECT a.salary FROM Author a WHERE a.magazine = auth.magazine)
Subqueries may be used in the
WHERE
or
HAVING
clause. The syntax for subqueries is as follows:
WHERE
and
HAVING
clauses in this
release. Support for subqueries in the
FROM
clause will be considered in a later release of the specification.
simple_select_clause ::= SELECT [DISTINCT] simple_select_expression
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_expression ::= single_valued_path_expression | aggregate_expression | identification_variable
SELECT DISTINCT auth FROM Author auth
WHERE EXISTS (SELECT spouseAuth FROM Author spouseAuth WHERE spouseAuth = auth.spouse)
SELECT mag FROM Magazine mag
WHERE (SELECT COUNT(art) FROM mag.articles art) > 10
Note that some contexts in which
a subquery can be used require that the subquery be a scalar subquery
(i.e., produce a single result). This is illustrated in the following
example involving a numeric comparison operation.
SELECT goodPublisher FROM Publisher goodPublisher
WHERE goodPublisher.revenue < (SELECT AVG(p.revenue) FROM Publisher p)
The JPQL includes
the following built-in functions, which may be used in the
WHERE
or
HAVING
clause of a query. If the
value of any argument to a functional expression
is null or unknown, the value of the functional expression is unknown.
The
SELECT
clause denotes the query result. More than
one value may be returned from the
SELECT
clause of a query.
The
SELECT
clause may contain one or more of the following elements: a single
range variable or identification variable that ranges over an entity
abstract schema type, a single-valued path expression, an aggregate
select expression, a constructor expression. The
SELECT
clause has the
following syntax:
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)
SELECT pub.id, pub.revenue
FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
Note that the
SELECT
clause must be specified to return
only single-valued expressions. The query below is therefore not valid:
SELECT mag.authors FROM Magazine AS magThe
DISTINCT
keyword is used to specify that duplicate
values must be eliminated from the query result. If
DISTINCT
is not
specified, duplicate values are not eliminated. Standalone identification
variables in the
SELECT
clause may optionally be qualified by the
OBJECT
operator. The
SELECT
clause must not
use the OBJECT operator to qualify path expressions.
The type of the query result
specified by the
SELECT
clause of a query is an entity abstract schema
type, a state-field type, the result of an aggregate function, the result
of a construction operation, or some sequence of these. The result
type of the
SELECT
clause is defined by the the result types of the
select_expressions contained in it. When multiple select_expressions are
used in the
SELECT
clause, the result of the query is of type Object[],
and the elements in this result correspond in order to the order of
their specification in the
SELECT
clause and in type to the result
types of each of the select_expressions. The type of the result of a
select_expression is as follows:
A single_valued_path_expression that is a state_field_path_expression
results in an object of the same type as the corresponding state field
of the entity. If the state field of the entity is a primitive type,
the corresponding object type is returned.
single_valued_path_expression that is a
single_valued_association_path_expression results in an entity object
of the type of the relationship field or the subtype of the relationship
field of the entity object as determined by the object/relational mapping.
The result type of an identification_variable is the type of the
entity to which that identification variable corresponds or a subtype
as determined by the object/relational mapping.
The result type of aggregate_expression is defined in section
Section 10.2.7.4, “JPQL Aggregate Functions”
.
The result type of a constructor_expression is the type of the class
for which the constructor is defined. The types of the arguments to the
constructor are defined by the above rules.
SELECT NEW com.company.PublisherInfo(pub.id, pub.revenue, mag.price) FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
in the
SELECT
Clause The result of a query may
be the result of an aggregate function applied to a path expression. The
following aggregate functions can be used in the
SELECT
clause of a query:
AVG
,
COUNT
,
MAX
,
MIN
,
SUM
.
For all aggregate functions except
COUNT
,
the path expression that is the argument to the aggregate function must
terminate in a state-field. The path expression argument to
COUNT
may
terminate in either a state-field or a association-field, or the argument
to
COUNT
may be an identification variable. Arguments to the functions
SUM
and
AVG
must be numeric. Arguments
to the functions
MAX
and
MIN
must
correspond to orderable state-field types (i.e., numeric types, string
types, character types, or date types). The Java type that is contained
in the result of a query using an aggregate function is as follows:
COUNT
returns Long.
MAX
,
MIN
return the type of the state-field to
which they are applied.
AVG
returns Double.
SUM
returns Long when
applied to state-fields of integral types (other than BigInteger); Double
when applied to state-fields of floating point types; BigInteger when
applied to state-fields of type BigInteger; and BigDecimal when applied
to state-fields of type BigDecimal. If
SUM
,
AVG
,
MAX
, or
MIN
is used,
and there are no values to which the aggregate function can be applied,
the result of the aggregate function is
NULL
.
If
COUNT
is used, and
there are no values to which
COUNT
can be applied, the result of the
aggregate function is 0.
The argument to an aggregate function may be preceded by the keyword
DISTINCT
to specify that duplicate values are to be eliminated before
the aggregate function is applied. Null values are eliminated before
the aggregate function is applied, regardless of whether the keyword
DISTINCT
is specified.
Examples The following query returns the average price of all magazines:
SELECT AVG(mag.price) FROM Magazine magThe following query returns the sum total cost of all the prices from all the magazines published by 'Larry':
SELECT SUM(mag.price) FROM Publisher pub JOIN pub.magazines mag pub.firstName = 'Larry'The following query returns the total number of magazines:
SELECT COUNT(mag) FROM Magazine mag
WHERE
clause is
described in
Section 10.2.4, “JPQL WHERE Clause”
.
A delete operation only
applies to entities of the specified class and its subclasses. It does
not cascade to related entities. The new_value specified for an update
operation must be compatible in type with the state-field to which it
is assigned. Bulk update maps directly to a database update operation,
bypassing optimistic locking checks. Portable applications must manually
update the value of the version column, if desired, and/or manually
validate the value of the version column. The persistence context is
not synchronized with the result of the bulk update or delete. Caution
should be used when executing bulk update or delete operations because
they may result in inconsistencies between the database and the entities
in the active persistence context. In general, bulk update and delete
operations should only be performed within a separate transaction or
at the beginning of a transaction (before entities have been accessed
whose state might be affected by such operations).
DELETE FROM Publisher pub WHERE pub.revenue > 1000000.0
DELETE FROM Publisher pub WHERE pub.revenue = 0 AND pub.magazines IS EMPTY
UPDATE Publisher pub SET pub.status = 'outstanding'
WHERE pub.revenue < 1000000 AND 20 > (SELECT COUNT(mag) FROM pub.magazines mag)