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 317 Java Persistence API 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 complete BNF for JPQL is defined in Section 2.13, “ JPQL BNF ”. Any JPQL statement may be constructed dynamically or may be statically defined in a metadata annotation or XML descriptor element. All statement types may have parameters, as discussed in Section 2.5.4, “ JPQL Input Parameters ”.
A select statement is a string which consists of the following clauses:
a SELECT
clause, which determines the type of the objects
or values to be selected.
a FROM
clause, which provides declarations that designate the
domain to which the expressions specified in the other clauses of the query
apply.
an optional WHERE
clause, which may be used to restrict the
results that are returned by the query.
an optional GROUP BY
clause, which allows query results to be
aggregated in terms of groups.
an optional HAVING
clause, which allows filtering over
aggregated groups.
an optional ORDER BY
clause, which may be used to order the
results that are returned by the query.
In BNF syntax, a select statement is defined as:
select_statement ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]
A select statement must always have a SELECT
and a
FROM
clause. The square brackets [] indicate that the other
clauses are optional.
Update and delete statements provide bulk operations over sets of entities. In BNF syntax, these operations are defined as:
update_statement ::= update_clause [where_clause]
delete_statement ::= delete_clause [where_clause]
The update and delete clauses determine the type of the entities to be updated
or deleted. The WHERE
clause may be used to restrict the
scope of the update or delete operation. Update and delete statements are
described further in Section 2.10, “
JPQL Bulk Update and Delete
”.
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 or embeddable 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 or embeddable 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 and embeddables 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 and associated embeddable classes on which it is based. The association-fields of an entity's
or embeddable'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.
Entities are designated in query strings by their entity names. The entity name is defined by the name element of the Entity annotation (or the entity-name XML descriptor element), and defaults to the unqualified name of the entity class. Entity names are scoped within the persistence unit and must be unique within the persistence unit.
This example assumes that the application developer provides several entity
classes, representing magazines, publishers, authors, and articles. The abstract
schema types for these entities are Magazine
,
Publisher
, Author
, and Article
.
Several Entities with Abstract Persistence Schemas Defined in the Same
Persistence Unit. The entity Publisher
has a one-to-many
relationships with Magazine
. There is also a one-to-many
relationship between Magazine
and Article
. The entity Article
is related to Author
in a one-to-one relationship.
Queries to select magazines can be defined by navigating over the
association-fields and state-fields defined by Magazine
and
Author
. A query to
find all magazines that have unpublished articles is as follows:
SELECT DISTINCT mag FROM Magazine AS mag JOIN mag.articles AS art WHERE art.published = FALSE
This 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 not 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 (See section Section 2.3.4, “
JPQL 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_collection_valued_path_expression::= identification_variable.{single_valued_embeddable_object_field.}*collection_valued_field
join_single_valued_path_expression::= identification_variable.{single_valued_embeddable_object_field.}*single_valued_object_field
join_spec ::= [ LEFT [OUTER] | INNER ] JOIN
collection_member_declaration ::= IN (collection_valued_path_expression) [AS] identification_variable
The following subsections discuss the constructs used in the FROM
clause.
An identifier is a character sequence of unlimited length. The character
sequence must begin with a Java identifier start character, and all other
characters must be Java identifier part characters. An identifier start
character is any character for which the method
Character.isJavaIdentifierStart
returns true
.
This includes the underscore (_) character and the dollar sign ($) character. An
identifier part character is any character for which the method
Character.isJavaIdentifierPart
returns true
.
The question mark (?) character is reserved for use by the Java Persistence
query language. The following are reserved identifiers:
ABS
ALL
AND
ANY
AS
ASC
AVG
BETWEEN
BOTH
BY
CASE
CLASS
COALESCE
CONCAT
COUNT
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
DELETE
DESC
DISTINCT
ELSE
EMPTY
END
ENTRY
ESCAPE
EXISTS
FALSE
FETCH
FROM
GROUP
HAVING
IN
INDEX
INNER
IS
JOIN
KEY
LEADING
LEFT
LENGTH
LIKE
LOCATE
LOWER
MAX
MEMBER
MIN
MOD
NEW
NOT
NULL
NULLIF
OBJECT
OF
OR
ORDER
OUTER
SELECT
SET
SIZE
SOME
SQRT
SIBSTRING
SUM
THEN
TRAILING
TRIM
TRUE
TYPE
UPDATE
UPPER
VALUE
WHEN
WHERE
CHARACTER_LENGTH
CHAR_LENGTH
BIT_LENGTH
POSITION
UNKNOWN
Reserved identifiers are case insensitive. Reserved identifiers must not be used as identification variables or result variables.
It is recommended that other SQL reserved words also not be as identification variables in queries because they may be used as reserved identifiers in future releases of the specification.
BIT_LENGTH, CHAR_LENGTH, CHARACTER_LENGTH, POSITION, and UNKNOWN are not currently used: they are reserved for future use.
An identification variable is a valid identifier declared in the FROM
clause of a query.
All identification variables must be declared in
the FROM
clause. Identification variables cannot be declared
in other clauses.
An identification variable must not be a reserved identifier or have the same name as any entity in the same persistence unit.
Identification variables are case insensitive.
An identification variable evaluates to a value of the type of the expression used in declaring the variable. For example, consider the previous query:
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 can range over an entity, embeddable, or basic abstract schema type. An identification variable designates an instance of an entity abstract schema type or an element of a collection of entity abstract schema type instances.
Note that for identification variables referring to an instance of an association or collection represented
as a java.util.Map
, the identification variable is of the abstract schema type of the map
value
.
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.
All identification variables used in the SELECT
,
WHERE
,
ORDER BY
,
GROUP BY
, or
HAVING
clause of a SELECT
or
DELETE
statement must be declared in the FROM
clause.
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 these clauses. 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.
An identification variable is scoped to the query (or subquery) in which it is defined and is also visible to any subqueries within that query scope that do not define an identification variable of the same name.
The syntax for declaring an identification variable as a range variable is similar to that of SQL; optionally, it uses the AS keyword. A range variable designates an entity abstract schema type.
A range variable must not designate an embeddable class abstract schema type.
range_variable_declaration ::= entity_name [AS] identification_variable
Range variable declarations allow the developer to designate a "root" for objects which may not be reachable by navigation.
In order to select values by
comparing more than one instance of an entity abstract schema type, more than
one identification variable ranging over the abstract schema type is needed in
the FROM
clause.
The following query returns magazines whose price is greater than the price of
magazines published by "Adventure" publishers. This example illustrates the use
of two different identification variables in the FROM
clause,
both of the abstract schema type Magazine. The SELECT
clause
of this query determines that it is the magazines with prices greater than those
of "Adventure" publisher's that are returned.
SELECT DISTINCT mag1 FROM Magazine mag1, Magazine mag2 WHERE mag1.price > mag2.price AND mag2.publisher.name = 'Adventure'
An identification variable followed by the navigation operator (.) and a state-field or association-field is a path expression. The type of the path expression is the type computed as the result of navigation; that is, the type of the state-field or association-field to which the expression navigates.
An identification variable qualified by the KEY
,
VALUE
, or ENTRY
operator is a path expression. The
KEY
, VALUE
,
and ENTRY
operators may only be applied to identification variables that correspond to
map-valued associations or map-valued element collections. The type of the path expression is the type
computed as the result of the operation; that is, the abstract schema type of the field that is the value of
the KEY
,
VALUE
, or ENTRY
operator (the map key, map value, or map entry respectively).
Note that use of VALUE
is optional,
as an identification variable referring to an association of type
java.util.Map
is of the
abstract schema type of the map value.
The syntax for qualified identification variables is as follows.
qualified_identification_variable :: = KEY(identification_variable) | VALUE(identification_variable) | ENTRY(identification_variable)
A path expression using the KEY
or VALUE
operator may be further composed. A path expression
using the ENTRY
operator is terminal.
It cannot be further composed and can only appear in the
SELECT
list of a query.
In the following query, photos
is a map from photo label to filename.
SELECT i.name, VALUE(p) FROM Item i JOIN i.photos p WHERE KEY(p) LIKE ‘egret’
In the above query the identification variable p
designates
an abstract schema type corresponding to the
map value. The results of VALUE(p)
and KEY(p)
are the map value and the map key associated with
p, respectively. The following query is equivalent:
SELECT i.name, p FROM Item i JOIN i.photos p WHERE KEY(p) LIKE ‘egret’
Depending on navigability, a path expression that leads to a association-field or to a field whose type is an embeddable class may be further composed. Path expressions can be composed from other path expressions if the original path expression evaluates to a single-valued type (not a collection) corresponding to a association-field.
In the following example, contactInfo
denotes an embeddable
class consisting of an address and
set of phones. Phone
is an entity.
SELECT p.vendor FROM Employee e JOIN e.contactInfo.phones p WHERE e.contactInfo.address.zipcode = '95054'
Path expression navigability is composed using "inner join" semantics. That is, if the value of a non-terminal association-field in the path expression is null, the path is considered to have no value, and does not participate in the determination of the result.
The following query is equivalent to the query above:
SELECT p.vendor FROM Employee e JOIN e.contactInfo c JOIN c.phones p WHERE e.contactInfo.address.zipcode = '95054'
The syntax for single-valued path expressions and collection valued path expressions is as follows:
single_valued_path_expression ::= qualified_identification_variable | state_field_path_expression | single_valued_object_path_expression
state_field_path_expression ::= general_identification_variable.{single_valued_object_field.}*state_field
single_valued_object_path_expression ::= general_identification_variable.{single_valued_object_field.}*single_valued_object_field
collection_valued_path_expression ::= general_identification_variable.{single_valued_object_field.}*collection_valued_field
A single_valued_object_field
is designated by the name of an
association-field in a one-to-one or many-to-one relationship
or a field of embeddable class type. The type of a
single_valued_object_field
is the abstract schema type of the
related entity or embeddable class.
A state_field
is designated by the name of an entity or
embeddable class state field that corresponds to
a basic type.
A collection_valued_field is designated by the name
of an association-field in a one-to-many or a many-to-many relationship
or by the name of an element collection field. The
type of a collection_valued_field
is
a collection of values of the
abstract schema type of the related entity
or element type.
An identification variable used in a
single_valued_object_path_expression
or in a
collection_valued_path_expression
may be an unqualified identification variable or an identification
variable to which the KEY or VALUE function has been applied.
general_identification_variable ::= identification_variable | KEY(identification_variable) | VALUE(identification_variable)
It is syntactically illegal to compose a path expression from a
path expression that evaluates to a collection. For example, if mag
designates 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
It is illegal to use a collection_valued_path_expression
other than
in the FROM
clause of a query
except in an empty_collection_comparison_expression
,
in a collection_member_expression
, or
as an argument to the SIZE
operator.
See Section 2.5.12, “
JPQL Empty Collection Comparison Expressions
”, Section 2.5.13, “
JPQL Collection Member Expressions
”,
and Section 2.6.2.2, “
JPQL Arithmetic Functions
”.
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. In the absence of a join condition, this reduces to the cartesian product.
The main use case for this generalized style of join is when a join condition does not involve a foreign key relationship that is mapped to an entity relationship. For Example,
SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize
In general, use of this style of inner join (also referred to as theta-join) is less typical than explicitly defined joins over relationships.
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_path_expression
join_collection_valued_path_expression::= identification_variable.{single_valued_embeddable_object_field.}*collection_valued_field
join_single_valued_path_expression::= identification_variable.{single_valued_embeddable_object_field.}*single_valued_object_field
join_spec ::= [ LEFT [OUTER] | INNER ] JOIN
The inner and outer join operation types described in Section 2.3.5.1, “ JPQL Inner Joins (Relationship Joins) ” and Section 2.3.5.2, “ JPQL Outer Joins ” are supported.
The syntax for the inner join operation is
For example, the query below joins over the relationship between publishers and magazines. This type of join typically equates to a join over a foreign key relationship in the database.
SELECT pub FROM Publisher pub JOIN pub.magazines mag WHERE pub.revenue > 1000000
The keyword INNER
may optionally be used:
SELECT pub FROM Publisher pub INNER JOIN pub.magazines mag WHERE pub.revenue > 1000000
This 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
The query below joins over Employee, ContactInfo and Phone. ContactInfo is an embeddable class that consists of an address and set of phones. Phone is an entity.
SELECT p.vendor FROM Employee e JOIN e.contactInfo c JOIN c.phones p WHERE c.address.zipcode = '95054'
LEFT JOIN
and LEFT OUTER JOIN
are
synonymous. They enable the retrieval of a set of entities where matching values
in the join condition may be absent. The syntax for a left outer join is:
For example:
SELECT pub FROM Publisher pub LEFT JOIN pub.magazines mag WHERE pub.revenue > 1000000
The keyword OUTER
may optionally be used:
SELECT pub FROM Publisher pub LEFT OUTER JOIN pub.magazines mags WHERE pub.revenue > 1000000
An 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
.
A FETCH JOIN
enables the fetching of an association as a side
effect of the execution of a query. A FETCH JOIN
is specified
over an entity and its related entities. The syntax for a fetch join is
fetch_join ::= [ LEFT [OUTER] | INNER ] JOIN FETCH join_association_path_expression
The association referenced by the right side of the FETCH JOIN
clause must be an association that belongs to an entity that is
returned as a result of the query. It is not permitted to specify an
identification variable for the entities referenced by the right side of the
FETCH JOIN
clause, and hence references to the implicitly
fetched entities cannot appear elsewhere in the query.
The following query
returns a set of magazines. As a side effect, the associated articles for those
magazines are also retrieved, even though they are not part of the explicit
query result. The persistent fields or properties of the articles that are
eagerly fetched are fully initialized. The initialization of the relationship
properties of the articles
that are retrieved is determined
by the metadata for the Article
entity class.
SELECT mag FROM Magazine mag LEFT JOIN FETCH mag.articles WHERE mag.id = 1
A fetch join has the same join semantics as the corresponding inner or outer join, except that the related objects specified on the right-hand side of the join operation are not returned in the query result or otherwise referenced in the query. Hence, for example, if magazine id 1 has five articles, the above query returns five references to the magazine 1 entity.
The FETCH JOIN
construct must not be used in the FROM clause of a subquery.
An identification variable declared by a collection_member_declaration
ranges
over values of a collection obtained by navigation using a path expression. Such
a path expression represents a navigation involving the association-fields of an
entity abstract schema type. Because a path expression can be based on another
path expression, the navigation can use the association-fields of related
entities.
An identification variable of a collection member declaration is
declared using a special operator, the reserved identifier IN
. The argument to the IN
operator is a collection-valued path
expression. The path expression evaluates to a collection type specified as a
result of navigation to a collection-valued association-field of an entity
or embeddable class
abstract schema type.
The syntax for declaring a collection member identification variable is as follows:
collection_member_declaration ::= IN (collection_valued_path_expression) [AS] identification_variable
For example, the query
SELECT DISTINCT mag FROM Magazine mag JOIN mag.articles art JOIN art.author auth WHERE auth.lastName = 'Grisham'
can equivalently be
expressed as follows, using the IN
operator:
SELECT DISTINCT mag FROM Magazine mag, IN(mag.articles) art WHERE art.author.lastName = 'Grisham'
In this example,
articles
is the name of an association-field whose value is a
collection of instances of the abstract schema type Article
.
The identification variable art
designates a member of this
collection, a single Article
abstract schema type instance.
In this example, mag
is an identification variable of the
abstract schema type Magazine
.
The Java Persistence query language treats the FROM clause similarly to SQL in that the declared identification variables affect the results of the query even if they are not used in the WHERE clause. Application developers should use caution in defining identification variables because the domain of the query can depend on whether there are any values of the declared type.
For example, the FROM
clause below defines a query over
all orders that have line items and existing
products. If there are no Product
instances in the database,
the domain of the query is empty and no
order is selected.
SELECT o FROM Order AS o JOIN o.lineItems l JOIN l.product p
Java Persistence queries are automatically polymorphic. The FROM
clause of a query designates not only instances of the specific
entity classes to which explicitly refers but of subclasses as well. The
instances returned by a query include instances of the subclasses that satisfy
the query criteria.
Non-polymorphic queries or queries whose polymorphism is restricted can be specified using entity
type expressions in the WHERE
clause to restrict the domain of the query.
See Section 2.6.4, “
Entity Type Expressions
”.
The WHERE
clause of a query consists of a conditional
expression used to select objects or values that satisfy the expression. The
WHERE
clause restricts the result of a select statement or
the scope of an update or delete operation.
A WHERE
clause is
defined as follows:
where_clause ::= WHERE conditional_expression
The 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
The GROUP BY
and HAVING
constructs are
further discussed in Section 2.7, “
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.
A string literal is enclosed in single quotes--for example: 'literal'. A string literal that includes a single quote is represented by two single quotes--for example: 'literal''s'. String literals in queries, like Java String literals, use unicode character encoding. The use of Java escape notation is not supported in query string literals.
Exact numeric literals support the use of Java integer literal syntax as well as SQL exact numeric literal syntax.
Approximate literals support the use of Java floating point literal syntax as well as SQL approximate numeric literal syntax.
Enum literals support the use of Java enum literal syntax. The enum class name must be specified.
Appropriate suffixes can be used
to indicate the specific type of a numeric literal in accordance with the Java
Language Specification. The boolean literals are TRUE
and
FALSE
. Although predefined reserved literals appear in upper
case, they are case insensitive.
The JDBC escape syntax may be used for the specification of date, time, and timestamp literals. For example:
SELECT o FROM Customer c JOIN c.orders o WHERE c.name = 'Smith' AND o.submissionDate < {d '2008-12-31'}
Date, time, and timestamp literals are passed as it to the JDBC driver in use.
Entity type literals are specified by entity names—for example: Customer
.
Although reserved literals appear in upper case, they are case insensitive.
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 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.
It is illegal to use a collection_valued_path_expression
within a
WHERE
or HAVING
clause as part of a conditional
expression except in an empty_collection_comparison_expression
, in a
collection_member_expression
, or as an argument to the SIZE
operator.
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 2.11, “ JPQL Null Values ”.
All input parameters must be single-valued, except in IN expressions (see Section 2.5.9, “ JPQL In Expressions ” ), which support the use of collection-valued input parameters.
The following rules apply to positional parameters.
Input parameters are designated by the question mark (?) prefix followed by an integer. For example: ?1.
Input parameters are numbered starting from 1.
The same parameter can be used more than once in the query string.
The ordering of the use of parameters within the query string need not conform to the order of the positional parameters.
A named parameter is an identifier that is prefixed by the ":" symbol. It follows the rules for identifiers defined in Section 2.3.1, “ JPQL FROM Identifiers ”. Named parameters are case sensitive.
Example:
SELECT pub FROM Publisher pub WHERE pub.revenue > :rev
The same named parameter can be used more than once in the query string.
Conditional expressions are composed of other conditional expressions, comparison operations, logical operations, path expressions that evaluate to boolean values, boolean literals, and boolean input parameters.
The scalar expressions described in Section 2.6, “ JPQL Scalar Expressions ” can be used in conditional expressions.
Standard bracketing () for ordering expression evaluation is supported.
Aggregate functions can only be used in conditional expressions in a
HAVING
clause. See Section 2.7, “
JPQL GROUP BY, HAVING
”.
Conditional expressions are defined as follows:
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
The operators are listed below in order of decreasing precedence.
Navigation operator (.)
Arithmetic operators: +, - unary *, / multiplication and division +, - addition and subtraction
Comparison operators: =, >, >=, <, <=, <> (not equal), [
NOT
] BETWEEN
, [ NOT
]
LIKE
, [ NOT
] IN
,
IS
[ NOT
] NULL
,
IS
[ NOT
] EMPTY
, [
NOT
] MEMBER
[ OF
]
Logical operators: NOT
, AND
,
OR
The following sections describe other operators used in specific expressions.
The syntax for the use of comparison expressions in a conditional expression is as follows:
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} | entity_type_expression { = | <> } entity_type_expression}
comparison_operator ::= = | > | >= | < | <= | <>
Examples:
item.cost * 1.08 <= 100.00
CONCAT(person.lastName, ‘, ’, person.firstName)) = ‘Jones, Sam’
TYPE(e) = ExemptEmployee
The syntax for the use of the comparison operator [ NOT
]
BETWEEN
in a conditional expression is as follows:
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
The BETWEEN expression
x BETWEEN y AND z
is semantically equivalent to:
y <= x AND x <= z
The rules for unknown and NULL
values in
comparison operations apply. See Section 2.11, “
JPQL Null Values
”
.
Examples are:
p.age BETWEEN 15 and 19
is equivalent to:
p.age >= 15 AND p.age <= 19
The following expression:
p.age NOT BETWEEN 15 and 19
excludes the range, and is equivalent to:
p.age < 15 OR p.age > 19
In the following example, transactionHistory
is a list of credit card
transactions defined using an order column.
SELECT t FROM CreditCard c JOIN c.transactionHistory t WHERE c.holder.name = ‘John Doe’ AND INDEX(t) BETWEEN 0 AND 9
The syntax for the use of the comparison operator [ NOT
]
IN
in a conditional expression is as follows:
in_expression ::= state_field_path_expression [NOT] IN {( in_item {, in_item}* ) | (subquery) | collection_valued_input_parameter }
in_item ::= literal | single_valued_input_parameter
The state_field_path_expression
must have a string, numeric,
date, time, timestamp, 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 2.12, “
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 2.5.16, “
JPQL Subqueries
”.
Examples:
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
or in_item
in an IN
or
NOT IN
expression is NULL
or unknown, the value of
the expression is unknown.
Note that use of a collection-valued input parameter will mean that a static query cannot be precompiled.
The syntax for the use of the comparison operator [ NOT
]
LIKE
in a conditional expression is as follows:
like_expression ::=
string_expression [NOT] LIKE pattern_value
[ESCAPE escape_character
]
The string_expression
must have a string value.
The pattern_value
is a string
literal or a string-valued input parameter in which an underscore (_) stands for
any single character, a percent (%) character stands for any sequence of
characters (including the empty sequence), and all other characters stand for
themselves. The optional escape_character is a single-character string literal
or a character-valued input parameter (i.e., char or Character) and is used to
escape the special meaning of the underscore and percent characters in
pattern_value.
Examples:
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.
The syntax for the use of the comparison operator IS NULL
in
a conditional expression is as follows:
null_comparison_expression ::= {single_valued_path_expression | input_parameter } IS [NOT] NULL
A null comparison expression tests whether or not the single-valued path
expression or input parameter is a NULL
value.
Null comparisons over instances of embeddable class types are not supported.
The syntax for the use of the comparison operator IS EMPTY
in
an empty_collection_comparison_expression
is as follows:
empty_collection_comparison_expression ::= collection_valued_path_expression IS [NOT] EMPTY
This expression tests whether or not the collection designated by the collection-valued path expression is empty (i.e. has no elements).
For example, the following query will return all magazines that don't have any articles at all:
SELECT mag FROM Magazine mag WHERE mag.articles IS EMPTY
If 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.
The syntax for the use of the comparison operator MEMBER OF
in an collection_member_expression
is as follows:
collection_member_expression ::= entity_or_value_expression [NOT] MEMBER [OF] collection_valued_path_expression
entity_or_value_expression ::= single_valued_object_path_expression | state_field_path_expression | simple_entity_or_value_expression
simple_entity_or_value_expression ::= identification_variable | input_parameter | literal
This expression tests whether the designated value is a member of the collection specified by the collection-valued path expression.
Expressions that evaluate to embeddable types are not supported in collection member expressions.
If the collection valued
path expression designates an empty collection, the value of the
MEMBER OF
expression is FALSE
and the value of the
NOT MEMBER OF
expression is TRUE
.
Otherwise, if the value of the collection_valued_path_expression
or
entity_or_value_expression
in the collection member
expression is NULL
or unknown, the value of the collection
member expression is unknown.
The use of the reserved word OF is optional in this expression.
Example:
SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames
An EXISTS
expression is a predicate that is true only if the
result of the subquery consists of one or more values and that is false
otherwise. The syntax of an exists expression is
exists_expression ::= [NOT] EXISTS (subquery)
Example:
SELECT DISTINCT auth FROM Author auth WHERE EXISTS (SELECT spouseAuthor FROM Author spouseAuthor WHERE spouseAuthor = auth.spouse)
The result of this query consists of all authors whose spouse is also an author.
An ALL
conditional expression is a predicate
over a subquery 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
value of the result of the subquery,
and is unknown if neither true nor false.
An ANY
conditional expression is a predicate over a subquery 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 2.12, “
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)
The following example select the authors who make the highest salary for their magazine:
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:
subquery ::= simple_select_clause subquery_from_clause [where_clause] [groupby_clause] [having_clause]
simple_select_clause ::= SELECT [DISTINCT] simple_select_expression
subquery_from_clause ::= FROM subselect_identification_variable_declaration {, subselect_identification_variable_declaration | collection_member_declaration }*
subselect_identification_variable_declaration ::= identification_variable_declaration | derived_path_expression [AS] identification_variable {join}* | derived_collection_member_declaration
simple_select_expression ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable
derived_path_expression ::= superquery_identification_variable.{single_valued_object_field.}*collection_valued_field | superquery_identification_variable.{single_valued_object_field.}*single_valued_object_field
derived_collection_member_declaration ::= IN superquery_identification_variable.{single_valued_object_field.}*collection_valued_field
Subqueries are restricted to the WHERE
and HAVING
clauses in this release. Support for subqueries in the FROM
clause will be considered in a later release of the specification.
Examples:
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)
SELECT goodCustomer FROM Customer goodCustomer WHERE goodCustomer.balanceOwed < ( SELECT AVG(c.balanceOwed)/2.0 FROM Customer c)
Numeric, string, datetime, case, and entity type expressions result in scalar values.
Scalar expressions may be used in the SELECT
clause of a query as well as in the
WHERE
and HAVING
clauses.
scalar_expression::= arithmetic_expression | string_primary | enum_primary | datetime_primary | boolean_primary | case_expression | entity_type_expression
The arithmetic operators are:
Arithmetic operations use numeric promotion.
Arithmetic functions are described in Section 2.6.2.2, “ JPQL Arithmetic Functions ”.
JPQL includes the built-in functions described in subsections
Section 2.6.2.1, “
JPQL String Functions
”,
Section 2.6.2.2, “
JPQL Arithmetic Functions
”,
Section 2.6.2.3, “
JPQL Datetime Functions
”,
which may be used in the SELECT
,
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.
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
functions_returning_numerics ::= LENGTH(string_primary) | LOCATE(string_primary, string_primary[, simple_arithmetic_expression])
The CONCAT
function returns a string that is a concatenation
of its arguments.
The second and third arguments of the SUBSTRING
function denote the starting position and length of the substring to
be returned. These arguments are integers.
The third argument is optional. If it is not specified,
the substring from the start position to the end of the string is returned.
The first position of a string is
denoted by 1. The SUBSTRING
function returns a string.
The
TRIM
function trims the specified character from a string. If
the character to be trimmed is not specified, it is assumed to be space (or
blank). The optional trim_character is a single-character string literal or a
character-valued input parameter (i.e., char or Character). If a trim
specification is not provided, BOTH
is assumed. The
TRIM
function returns the trimmed string.
The LOWER
and UPPER
functions convert a string to lower and upper case,
respectively. They return a string.
The LOCATE
function
returns the position of a given string within a string, starting the search at a
specified position. It returns the first position at which the string was found
as an integer. The first argument is the string to be located; the second
argument is the string to be searched; the optional third argument is an integer
that represents the string position at which the search is started (by default,
the beginning of the string to be searched). The first position in a string is
denoted by 1. If the string is not found, 0 is returned.
The LENGTH
function returns the length of the string in characters as an
integer.
functions_returning_numerics ::= ABS(simple_arithmetic_expression) | SQRT(simple_arithmetic_expression) | MOD(simple_arithmetic_expression, simple_arithmetic_expression) | SIZE(collection_valued_path_expression) | INDEX(identification_variable)
The ABS
function takes a numeric argument and returns a
number (integer, float, or double) of the same type as the argument to the
function.
The SQRT
function takes a numeric argument and
returns a double.
Note that not all databases support the use of a trim character other than the
space character; use of this argument may result in queries that are not
portable. Note that not all databases support the use of the third argument to
LOCATE
; use of this argument may result in queries that are
not portable.
The MOD
function takes two integer arguments and returns an
integer.
The SIZE
function returns an integer value, the
number of elements of the collection. If the collection is empty, the
SIZE
function evaluates to zero. Numeric arguments to these functions
may correspond to the numeric Java object types as well as the primitive numeric
types.
The INDEX function returns an integer value corresponding to the position of its argument in an ordered list. The INDEX function can only be applied to identification variables denoting types for which an order column has been specified.
The following forms of case expressions are supported: general case expressions, simple case expressions, coalesce expressions, and nullif expressions.
CASE
ELSE
END
CASE
when_clause {when_clause}* ELSE
scalar_expression END
WHEN
conditional_expression THEN
scalar_expression
WHEN
scalar_expression THEN
scalar_expression
COALESCE
(scalar_expression {, scalar_expression}+)
NULLIF
(scalar_expression, scalar_expression)
Examples:
UPDATE Employee e SET e.salary = CASE WHEN e.rating = 1 THEN e.salary * 1.1 WHEN e.rating = 2 THEN e.salary * 1.05 ELSE e.salary * 1.01 END
UPDATE Employee e SET e.salary = CASE e.rating WHEN 1 THEN e.salary * 1.1 WHEN 2 THEN e.salary * 1.05 ELSE e.salary * 1.01 END
SELECT e.name, CASE TYPE(e) WHEN Exempt THEN 'Exempt' WHEN Contractor THEN 'Contractor' WHEN Intern THEN 'Intern' ELSE 'NonExempt' END FROM Employee e WHERE e.dept.name = 'Engineering'
SELECT e.name, f.name, CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum ' WHEN f.annualMiles > 25000 THEN 'Gold ' ELSE '' END, 'Frequent Flyer') FROM Employee e JOIN e.frequentFlierPlan f
An entity type expression can be used to restrict query polymorphism.
The TYPE
operator returns the
exact type of the argument.
The syntax of an entity type expression is as follows:
An entity_type_literal
is designated by the entity name.
The Java class of the entity is used as an input parameter to specify the entity type.
Examples:
SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor)
SELECT e FROM Employee e WHERE TYPE(e) IN (:empType1, :empType2)
SELECT e FROM Employee e WHERE TYPE(e) IN :empTypes
SELECT TYPE(e) FROM Employee e WHERE TYPE(e) <> Exempt
The GROUP BY
construct enables the aggregation of values
according to a set of properties. The HAVING
construct
enables conditions to be specified that further restrict the query result. Such
conditions are restrictions upon the groups.
The syntax of the GROUP
BY
and HAVING
clauses is as follows:
groupby_clause ::= GROUP BY groupby_item {, groupby_item}*
groupby_item ::= single_valued_path_expression | identification_variable
having_clause ::= HAVING conditional_expression
If a query contains both a WHERE
clause and a GROUP
BY
clause, the effect is that of first applying the where clause, and
then forming the groups and filtering them according to the HAVING
clause. The HAVING
clause causes those groups to
be retained that satisfy the condition of the HAVING
clause.
The requirements for the SELECT
clause when GROUP
BY
is used follow those of SQL: namely, any item that appears in the
SELECT
clause (other than as an argument to an aggregate
function) must also appear in the GROUP BY
clause. In forming
the groups, null values are treated as the same for grouping purposes.
Grouping by an entity is permitted. In this case, the entity must contain no serialized state fields or lob-valued state fields that are eagerly fetched.
Grouping by embeddables is not supported.
The HAVING
clause
must specify search conditions over the grouping items or aggregate functions
that apply to grouping items.
If there is no GROUP BY
clause and the HAVING
clause is used, the result is treated as a single group, and the
select list can only consist of aggregate functions. When a query declares a
HAVING
clause, it must always also declare a GROUP
BY
clause.
Examples:
SELECT c.status, AVG(c.filledOrderCount), COUNT(c) FROM Customer c GROUP BY c.status HAVING c.status IN (1, 2)
SELECT c.country, COUNT(c) FROM Customer c GROUP BY c.country HAVING COUNT(c) > 30
The SELECT
clause denotes the query result. More than one
value may be returned from the SELECT
clause of a query.
The SELECT
clause can 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,
a scalar expression,
an aggregate expression, a constructor expression.
The SELECT
clause has the following syntax:
select_clause ::= SELECT [DISTINCT] select_item {, select_item}*
select_item ::= select_expression [ [AS] result_variable]
select_expression ::= single_valued_path_expression | scalar_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 | scalar_expression | aggregate_expression | identification_variable
aggregate_expression ::= { AVG | MAX | MIN | SUM } ([DISTINCT] state_field_path_expression) | COUNT ([DISTINCT] identification_variable | state_field_path_expression | single_valued_object_path_expression)
For example:
SELECT pub.id, pub.revenue FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
In the following example, videoInventory is a Map from the entity Movie to the number of copies in stock:
SELECT v.location.street, KEY(i).title, VALUE(i) FROM VideoStore v JOIN v.videoInventory i WHERE v.location.zipcode = '94301' AND VALUE(i) > 0
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 mag
The 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.
The result of DISTINCT over embeddable objects or map entry results is undefined.
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.
A result_variable
may be used to name a select_item
in the query result.
For example,
SELECT c, COUNT(l) AS itemCount FROM Customer c JOIN c.Orders o JOIN o.lineItems l WHERE c.address.state = ‘CA’ ORDER BY itemCount
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 of a scalar expression, 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 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:
The result type of an identification_variable
is the type of the entity object or embeddable
object to which the identification variable corresponds. The type of an
identification_variable
that refers to an entity abstract schema type 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 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 or embeddable class.
If the state field of the entity is a
primitive type, the result type is the corresponding object type.
The result type of a single_valued_path_expression
that is a
single_valued_object_path_expression
is the type of the entity object or embeddable
object to which the path expression corresponds.
A single_valued_object_path_expression
that results in an entity object will result in an entity 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 a
single_valued_path_expression
that is an identification_variable to
which the KEY
or VALUE
function
has been applied is determined by the type of the map key
or value respectively, as defined by the above rules
The result type of a
single_valued_path_expression
that is an
identification_variable
to
which the ENTRY
function has been applied is
java.util.Map.Entry
, where the key
and value types of the map entry are determined by the above rules as applied to the map key
and map value respectively.
The result type of a
scalar_expression
is the type of the scalar value to which the expression
evaluates. The result type of a numeric scalar_expression
is defined in
Section 2.6, “
JPQL Scalar Expressions
”
The result type of an
entity_type_expression
scalar expression is the Java class to which the
resulting abstract schema type corresponds.
The result type of aggregate_expression is defined in Section 2.8.5, “ 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.
A constructor may be used in the
SELECT
list to return one or more Java instances. The
specified class is not required to be an entity or to be mapped to the database.
The constructor name must be fully qualified.
If an entity class name is specified in the SELECT NEW
clause, the resulting entity instances are in the new state.
If a single_valued_path_expression
or
identification_variable
that is an argument to the constructor
references an entity, the resulting entity instance referenced by that
single_valued_path_expression
or
identification_variable
will be in the managed state.
If PublisherInfo
is an entity class, the following 2 queries return
instances of PublisherInfo
that will be in the new state.
In the second example, mag
is an identification_variable
passed as an argument to the constructor PublisherInfo(Magazine mag)
;
the entity instances of Magazine
created during query evaluation
will be in the managed state.
Example:
SELECT NEW com.company.PublisherInfo(pub.id, pub.revenue, mag.price) FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
SELECT NEW com.company.PublisherInfo(mag) FROM Publisher pub JOIN pub.magazines mag WHERE mag.price > 5.00
If the result of a query corresponds to a association-field or state-field whose
value is null, that null value is returned in the result of the query method.
The IS NOT NULL
construct can be used to eliminate such null
values from the result set of the query.
Note, however, that state-field types
defined in terms of Java numeric primitive types cannot produce NULL
values in the query result. A query that returns such a state-field
type as a result type must not return a null value.
If the result of a query corresponds to an identification variable or state field whose value is an embeddable, the embeddable instance returned by the query will not be in the managed state (i.e., it will not be part of the state of any managed entity).
In the following example, the Address
instances returned by the query will reference Phone
instances. While the Phone
instances will be managed,
the Address
> instances referenced by the
addr
result variable will not be.
Modifications to these embeddable instances are not allowed.
@Entity public class Employee { @Id int id; Address address; ... } @Embeddable public class Address { String street; ... @OneToOne Phone phone; // fetch=EAGER } @Entity public class Phone { @Id int id; ... @OneToOne(mappedBy="address.phone") Employee emp; // fetch=EAGER } SELECT e.address AS addr FROM Employee e
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.
It is legal to specify DISTINCT
with MAX
or MIN
, but it does not affect the result.
Null values are eliminated before the
aggregate function is applied, regardless of whether the keyword
DISTINCT
is specified.
The use of DISTINCT
with COUNT
is not supported for arguments of
embeddable types or map entry types.
The following query returns the average price of all magazines:
SELECT AVG(mag.price) FROM Magazine mag
The following query returns the sum of all the prices from all the magazines published by 'Larry':
SELECT SUM(mag.price) FROM Publisher pub JOIN pub.magazines mag WHERE pub.firstName = 'Larry'
The following query returns the total number of magazines:
SELECT COUNT(mag) FROM Magazine mag
The type of a numeric expression in the query result is determined as follows:
An operand that corresponds to a persistent state-field is of the same type as that persistent state-field.
An operand that corresponds to one of arithmetic functions described in Section 2.6.2.2, “ JPQL Arithmetic Functions ” is of the type defined by Section 2.6.2.2, “ JPQL Arithmetic Functions ”.
An operand that corresponds to one of an aggregate functions described in Section 2.8.5, “ JPQL Aggregate Functions ” is of the type defined by Section 2.8.5, “ JPQL Aggregate Functions ”.
The result of a case expression, coalesce expression, nullif expression, or arithmetic expression (+, -, *, /) is determined by applying the following rule to its operands.
If there is an operand of type Double or double, the result of the operation is of type Double;
otherwise, if there is an operand of type Float or float, the result of the operation is of type Float;
otherwise, if there is an operand of type BigDecimal, the result of the operation is of type Big- Decimal;
otherwise, if there is an operand of type BigInteger, the result of the operation is of type BigInteger;
otherwise, if there is an operand of type Long or long, the result of the operation is of type Long;
otherwise, if there is an operand of integral type, the result of the operation is of type Integer.
The ORDER BY
clause allows the objects or values that are
returned by the query to be ordered. The syntax of the ORDER BY
clause is
orderby_clause ::= ORDER BY orderby_item {, orderby_item}*
orderby_item ::= { state_field_path_expression | result_variable } [ASC | DESC]
An orderby_item must be one of the following:
A state_field_path_expression
that evaluates to an orderable state field of an entity or
embeddable class abstract schema type designated in the SELECT clause by one of the following:
a general_identification_variable
a single_valued_object_path_expression
A state_field_path_expression
that evaluates to the same state field of the same entity or
embeddable abstract schema type as a state_field_path_expression
in the SELECT
clause.
A result_variable
that refers to an orderable item in the
SELECT
clause for which the same
result_variable
has been specified.
This may be the result of an aggregate_expression
, a
scalar_expression
,
or a state_field_path_expression
in the SELECT
clause.
For example, the five queries below are legal.
SELECT pub FROM Publisher pub ORDER BY pub.revenue, pub.name
SELECT o FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = ‘CA’ ORDER BY o.quantity DESC, o.totalcost
SELECT o.quantity, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = ‘CA’ ORDER BY o.quantity, a.zipcode
SELECT o.quantity, o.cost*1.08 AS taxedCost, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = ‘CA’ AND a.county = ‘Santa Clara’ ORDER BY o.quantity, taxedCost, a.zipcode
SELECT AVG(o.quantity) as q, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = ‘CA’ GROUP BY a.zipcode ORDER BY q DESC
The following two queries are not legal because the orderby_item
is not reflected in the SELECT
clause of the query.
SELECT p.product_name FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c WHERE c.lastname = ‘Smith’ AND c.firstname = ‘John’ ORDER BY p.price
SELECT p.product_name FROM Order o, IN(o.lineItems) l JOIN o.customer c WHERE c.lastname = ‘Smith’ AND c.firstname = ‘John’ ORDER BY o.quantity
If more than one orderby_item
is specified, the left-to-right
sequence of the orderby_item
elements determines the precedence, whereby the
leftmost orderby_item
has highest precedence.
The keyword ASC
specifies that ascending ordering be used; the keyword DESC
specifies that descending ordering be used. Ascending ordering is the default.
SQL rules for the ordering of null values apply: that is, all null values must appear before all non-null values in the ordering or all null values must appear after all non-null values in the ordering, but it is not specified which.
The
ordering of the query result is preserved in the result of the query method if
the ORDER BY
clause is used.
Bulk update and delete operations apply to entities of a single
entity class (together with its subclasses, if any). Only one entity abstract
schema type may be specified in the FROM
or UPDATE
clause. The syntax of these operations is as follows:
update_statement ::= update_clause [where_clause]
update_clause ::= UPDATE entity_name [[AS] identification_variable] SET update_item {, update_item}*
update_item ::= [identification_variable.]{state_field | single_valued_object_field} = new_value
new_value ::= scalar_expression | simple_entity_expression | NULL
delete_statement ::= delete_clause [where_clause]
delete_clause ::= DELETE FROM entity_name [[AS] identification_variable]
The syntax of the WHERE
clause is described in
Section 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 transaction in a new persistence context or at the beginning of a transaction (before entities have been accessed whose state might be affected by such operations).
Examples:
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)
When the target of a reference does not exist in the database, its value is
regarded as NULL
. SQL 92 NULL
semantics
defines the evaluation of conditional expressions containing NULL
values. The following is a brief description of these semantics:
Comparison or arithmetic operations with a
NULL
value always yield an unknown value.
Two NULL
values are not considered to be equal, the
comparison yields an unknown value.
Comparison or arithmetic operations with an unknown value always yield an unknown value.
The IS NULL
and IS NOT NULL
operators
convert a NULL
state-field or single-valued association-field
value into the respective TRUE
or FALSE
value.
Note: The JPQL defines the empty string, "", as a string with 0 length, which is
not equal to a NULL
value. However, NULL
values and empty strings may not always be distinguished when queries are mapped
to some databases. Application developers should therefore not rely on the
semantics of query comparisons involving the empty string and NULL
value.
Only the values of like
types are permitted to be compared. A type is like
another type if they correspond to the same Java language type, or if one is a
primitive Java language type and the other is the wrappered Java class type
equivalent (e.g., int
and Integer
are like types in this sense). There is one
exception to this rule: it is valid to compare numeric values for which the
rules of numeric promotion apply. Conditional expressions attempting to compare
non-like type values are disallowed except for this numeric case.
Note that the arithmetic operators and comparison operators are permitted to be applied to state-fields and input parameters of the wrappered Java class equivalents to the primitive numeric Java types.
Two entities of the same abstract schema type are equal if and only if they have the same primary key value.
Equality/inequality comparisons over enums are supported.
Comparisons over instances of embeddable class or map entry types are not supported.
The following is the BNF for the Java Persistence query language, from section 4.14 of the JSR 317 specification.
select_item ::= select_expression [[AS] result_variable]
QL_statement ::= select_statement | update_statement | delete_statement
select_statement ::= select_clause from_clause [where_clause] [groupby_clause] [having_clause] [orderby_clause]
update_statement ::= update_clause [where_clause]
delete_statement ::= delete_clause [where_clause]
from_clause ::= FROM
identification_variable_declaration {,
{identification_variable_declaration | collection_member_declaration}}*
identification_variable_declaration ::= range_variable_declaration { join | fetch_join }*
range_variable_declaration ::= entity_name [ AS
]
identification_variable
join ::= join_spec join_association_path_expression [ AS
]
identification_variable
fetch_join ::= join_spec FETCH
join_association_path_expression
join_spec ::= [ LEFT
[ OUTER
]|
INNER
] JOIN
join_association_path_expression ::= join_collection_valued_path_expression | join_single_valued_path_expression
join_collection_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}*collection_valued_field
join_single_valued_path_expression ::= identification_variable.{single_valued_embeddable_object_field.}*single_valued_object_field
collection_member_declaration ::= IN
(join_collection_valued_path_expression) [ AS
]
identification_variable
qualified_identification_variable ::= KEY(identification_variable) | VALUE(identification_variable) | ENTRY(identification_variable)
single_valued_path_expression ::= qualified_identification_variable | state_field_path_expression | single_valued_object_path_expression
general_identification_variable ::= identification_variable | KEY(identification_variable) | VALUE(identification_variable)
state_field_path_expression ::= general_identification_variable.{single_valued_object_field.}*state_field
single_valued_object_path_expression ::= general_identification_variable.{single_valued_object_field.}* single_valued_object_field
collection_valued_path_expression ::= general_identification_variable.{single_valued_object_field.}*collection_valued_field
update_clause ::= UPDATE
entity_name [[ AS
] identification_variable] SET
update_item {,
update_item}*
update_item ::= [identification_variable.]{state_field | single_valued_object_field}= new_value
new_value ::= scalar_expression |
simple_entity_expression | NULL
delete_clause ::= DELETE
FROM
entity_name [[ AS
] identification_variable]
select_clause ::= SELECT
[ DISTINCT
]
select_item {, select_item}*
select_expression ::= single_valued_path_expression |
scalar_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 | scalar_expression | aggregate_expression | identification_variable
aggregate_expression ::= { AVG
| MAX
|
MIN
| SUM
}([ DISTINCT
] state_field_path_expression) | COUNT
([ DISTINCT
] identification_variable | state_field_path_expression |
single_valued_object_path_expression)
where_clause ::= WHERE
conditional_expression
groupby_clause ::= GROUP
BY
groupby_item {,
groupby_item}*
groupby_item ::= single_valued_path_expression | identification_variable
having_clause ::= HAVING
conditional_expression
orderby_clause ::= ORDER
BY
orderby_item {,
orderby_item}*
orderby_item ::= state_field_path_expression | result_variable [ ASC
|
DESC
]
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 |
collection_member_declaration}*
subselect_identification_variable_declaration ::=
identification_variable_declaration | derived_path_expression [ AS
] identification_variable | derived_collection_member_declaration
derived_path_expression ::= superquery_identification_variable.{single_valued_object_field.}*collection_valued_field | superquery_identification_variable.{single_valued_object_field.}*single_valued_object_field
derived_collection_member_declaration ::= IN superquery_identification_variable.{single_valued_object_field.}*collection_valued_field
simple_select_clause ::= SELECT
[ DISTINCT
] simple_select_expression
simple_select_expression ::= single_valued_path_expression | scalar_expression | aggregate_expression | identification_variable
scalar_expression ::= simple_arithmetic_expression | string_primary | enum_primary | datetime_primary | boolean_primary | case_expression | entity_type_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 | type_discriminator} [ NOT
]
IN
{( in_item {, in_item}*) | (subquery) | collection_valued_input_parameter }
in_item ::= literal | single_valued_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
entity_or_value_expression ::= single_valued_object_path_expression | state_field_path_expression | simple_entity_or_value_expression
simple_entity_or_value_expression ::= identification_variable | input_parameter | literal
exists_expression ::= [ NOT
] EXISTS
(subquery)
all_or_any_expression ::= { ALL
| ANY
|
SOME
}(subquery)
comparison_expression ::= string_expressioncomparison_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} | entity_type_expression { =|<>>} entity_type_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 | case_expression
string_expression ::= string_primary |(subquery)
string_primary ::= state_field_path_expression | string_literal | input_parameter | functions_returning_strings | aggregate_expression | case_expression
datetime_expression ::= datetime_primary |(subquery)
datetime_primary ::= state_field_path_expression | input_parameter | functions_returning_datetime | aggregate_expression | case_expression | date_time_timestamp_literal
boolean_expression ::= boolean_primary |(subquery)
boolean_primary ::= state_field_path_expression | boolean_literal | input_parameter | case_expression
enum_expression ::= enum_primary |(subquery)
enum_primary ::= state_field_path_expression | enum_literal | input_parameter | case_expression
entity_expression ::= single_valued_object_path_expression | simple_entity_expression
simple_entity_expression ::= identification_variable | input_parameter
entity_type_expression ::= type_discriminator | entity_type_literal | input_parameter
type_discriminator ::=
TYPE
(identification_variable |
single_valued_object_path_expression |
input_parameter)
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) |
INDEX
(identification_variable)
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
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)