Chapter 14. HQL: The Hibernate Query Language
14.1. Case Sensitivity 14.2. The from clause 14.3. Associations and joins 14.4. Forms of join syntax 14.5. Referring to identifier property 14.6. The select clause 14.7. Aggregate functions 14.8. Polymorphic queries 14.9. The where clause 14.10. Expressions 14.11. The order by clause 14.12. The group by clause 14.13. Subqueries 14.14. HQL examples 14.15. Bulk update and delete 14.16. Tips & Tricks 14.17. Components 14.18. Row value constructor syntax
Hibernate uses a powerful query language (HQL) that is similar in appearance to SQL. Compared with SQL, however, HQL is fully object-oriented and understands notions like inheritance, polymorphism and association.
14.1. Case Sensitivity
With the exception of names of Java classes and properties, queries are case-insensitive. So SeLeCT
is the same as sELEct
is the same as SELECT
, but org.hibernate.eg.FOO
is not org.hibernate.eg.Foo
, and foo.barSet
is not foo.BARSET
.
This manual uses lowercase HQL keywords. Some users find queries with uppercase keywords more readable, but this convention is unsuitable for queries embedded in Java code.
14.2. The from clause
The simplest possible Hibernate query is of the form:
This returns all instances of the class eg.Cat
. You do not usually need to qualify the class name, since auto-import
is the default. For example:
In order to refer to the Cat
in other parts of the query, you will need to assign an alias. For example:
This query assigns the alias cat
to Cat
instances, so you can use that alias later in the query. The as
keyword is optional. You could also write:
Multiple classes can appear, resulting in a cartesian product or "cross" join.
It is good practice to name query aliases using an initial lowercase as this is consistent with Java naming standards for local variables (e.g. domesticCat
).
14.3. Associations and joins
You can also assign aliases to associated entities or to elements of a collection of values using a join
. For example:
The supported join types are borrowed from ANSI SQL:
-
inner join
-
left outer join
-
right outer join
-
full join
(not usually useful)
The inner join
, left outer join
and right outer join
constructs may be abbreviated.
You may supply extra join conditions using the HQL with
keyword.
A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select. This is particularly useful in the case of a collection. It effectively overrides the outer join and lazy declarations of the mapping file for associations and collections. See Section 19.1, “Fetching strategies” for more information.
A fetch join does not usually need to assign an alias, because the associated objects should not be used in the where
clause (or any other clause). The associated objects are also not returned directly in the query results. Instead, they may be accessed via the parent object. The only reason you might need an alias is if you are recursively join fetching a further collection:
The fetch
construct cannot be used in queries called using iterate()
(though scroll()
can be used). Fetch
should be used together with setMaxResults()
or setFirstResult()
, as these operations are based on the result rows which usually contain duplicates for eager collection fetching, hence, the number of rows is not what you would expect. Fetch
should also not be used together with impromptu with
condition. It is possible to create a cartesian product by join fetching more than one collection in a query, so take care in this case. Join fetching multiple collection roles can produce unexpected results for bag mappings, so user discretion is advised when formulating queries in this case. Finally, note that full join fetch
and right join fetch
are not meaningful.
If you are using property-level lazy fetching (with bytecode instrumentation), it is possible to force Hibernate to fetch the lazy properties in the first query immediately using fetch all properties
.
14.4. Forms of join syntax
HQL supports two forms of association joining: implicit
and explicit
.
The queries shown in the previous section all use the explicit
form, that is, where the join keyword is explicitly used in the from clause. This is the recommended form.
The implicit
form does not use the join keyword. Instead, the associations are "dereferenced" using dot-notation. implicit
joins can appear in any of the HQL clauses. implicit
join result in inner joins in the resulting SQL statement.
14.5. Referring to identifier property
There are 2 ways to refer to an entity's identifier property:
- The special property (lowercase)
id
may be used to reference the identifier property of an entity provided that the entity does not define a non-identifier property named id. - If the entity defines a named identifier property, you can use that property name.
References to composite identifier properties follow the same naming rules. If the entity has a non-identifier property named id, the composite identifier property can only be referenced by its defined named. Otherwise, the special id
property can be used to reference the identifier property.
Important
Please note that, starting in version 3.2.2, this has changed significantly. In previous versions, id
always referred to the identifier property regardless of its actual name. A ramification of that decision was that non-identifier properties named id
could never be referenced in Hibernate queries.
14.6. The select clause
The select
clause picks which objects and properties to return in the query result set. Consider the following:
The query will select mate
s of other Cat
s. You can express this query more compactly as:
Queries can return properties of any value type including properties of component type:
Queries can return multiple objects and/or properties as an array of type Object[]
:
Or as a List
:
Or - assuming that the class Family
has an appropriate constructor - as an actual typesafe Java object:
You can assign aliases to selected expressions using as
:
This is most useful when used together with select new map
:
This query returns a Map
from aliases to selected values.
14.7. Aggregate functions
HQL queries can even return the results of aggregate functions on properties:
The supported aggregate functions are:
-
avg(...), sum(...), min(...), max(...)
-
count(*)
-
count(...), count(distinct ...), count(all...)
You can use arithmetic operators, concatenation, and recognized SQL functions in the select clause:
The distinct
and all
keywords can be used and have the same semantics as in SQL.
14.8. Polymorphic queries
A query like:
returns instances not only of Cat
, but also of subclasses like DomesticCat
. Hibernate queries can name anyJava class or interface in the from
clause. The query will return instances of all persistent classes that extend that class or implement the interface. The following query would return all persistent objects:
The interface Named
might be implemented by various persistent classes:
These last two queries will require more than one SQL SELECT
. This means that the order by
clause does not correctly order the whole result set. It also means you cannot call these queries using Query.scroll()
.
14.9. The where clause
The where
clause allows you to refine the list of instances returned. If no alias exists, you can refer to properties by name:
If there is an alias, use a qualified property name:
This returns instances of Cat
named 'Fritz'.
The following query:
returns all instances of Foo
with an instance of bar
with a date
property equal to the startDate
property of theFoo
. Compound path expressions make the where
clause extremely powerful. Consider the following:
This query translates to an SQL query with a table (inner) join. For example:
would result in a query that would require four table joins in SQL.
The =
operator can be used to compare not only properties, but also instances:
The special property (lowercase) id
can be used to reference the unique identifier of an object. See Section 14.5, “Referring to identifier property” for more information.
The second query is efficient and does not require a table join.
Properties of composite identifiers can also be used. Consider the following example where Person
has composite identifiers consisting of country
and medicareNumber
:
Once again, the second query does not require a table join.
See Section 14.5, “Referring to identifier property” for more information regarding referencing identifier properties)
The special property class
accesses the discriminator value of an instance in the case of polymorphic persistence. A Java class name embedded in the where clause will be translated to its discriminator value.
You can also use components or composite user types, or properties of said component types. See Section 14.17, “Components” for more information.
An "any" type has the special properties id
and class
that allows you to express a join in the following way (where AuditLog.item
is a property mapped with <any>
):
The log.item.class
and payment.class
would refer to the values of completely different database columns in the above query.
14.10. Expressions
Expressions used in the where
clause include the following:
- mathematical operators:
+, -, *, /
- binary comparison operators:
=, >=, <=, <>, !=, like
- logical operations
and, or, not
- Parentheses
( )
that indicates grouping -
in
, not in
, between
, is null
, is not null
, is empty
, is not empty
, member of
and not member of
- "Simple" case,
case ... when ... then ... else ... end
, and "searched" case, case when ... then ... else ... end
- string concatenation
...||...
or concat(...,...)
-
current_date()
, current_time()
, and current_timestamp()
-
second(...)
, minute(...)
, hour(...)
, day(...)
, month(...)
, and year(...)
- Any function or operator defined by EJB-QL 3.0:
substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()
-
coalesce()
and nullif()
-
str()
for converting numeric or temporal values to a readable string -
cast(... as ...)
, where the second argument is the name of a Hibernate type, and extract(... from ...)
if ANSI cast()
and extract()
is supported by the underlying database - the HQL
index()
function, that applies to aliases of a joined indexed collection - HQL functions that take collection-valued path expressions:
size(), minelement(), maxelement(), minindex(), maxindex()
, along with the special elements()
and indices
functions that can be quantified using some, all, exists, any, in
. - Any database-supported SQL scalar function like
sign()
, trunc()
, rtrim()
, and sin()
- JDBC-style positional parameters
?
- named parameters
:name
, :start_date
, and :x1
- SQL literals
'foo'
, 69
, 6.66E+2
, '1970-01-01 10:00:01.0'
- Java
public static final
constants eg.Color.TABBY
in
and between
can be used as follows:
The negated forms can be written as follows:
Similarly, is null
and is not null
can be used to test for null values.
Booleans can be easily used in expressions by declaring HQL query substitutions in Hibernate configuration:
This will replace the keywords true
and false
with the literals 1
and 0
in the translated SQL from this HQL:
You can test the size of a collection with the special property size
or the special size()
function.
For indexed collections, you can refer to the minimum and maximum indices using minindex
and maxindex
functions. Similarly, you can refer to the minimum and maximum elements of a collection of basic type using the minelement
and maxelement
functions. For example:
The SQL functions any, some, all, exists, in
are supported when passed the element or index set of a collection (elements
and indices
functions) or the result of a subquery (see below):
Note that these constructs - size
, elements
, indices
, minindex
, maxindex
, minelement
, maxelement
- can only be used in the where clause in Hibernate3.
Elements of indexed collections (arrays, lists, and maps) can be referred to by index in a where clause only:
The expression inside []
can even be an arithmetic expression:
HQL also provides the built-in index()
function for elements of a one-to-many association or collection of values.
Scalar SQL functions supported by the underlying database can be used:
Consider how much longer and less readable the following query would be in SQL:
Hint: something like
14.11. The order by clause
The list returned by a query can be ordered by any property of a returned class or components:
The optional asc
or desc
indicate ascending or descending order respectively.
14.12. The group by clause
A query that returns aggregate values can be grouped by any property of a returned class or components:
A having
clause is also allowed.
SQL functions and aggregate functions are allowed in the having
and order by
clauses if they are supported by the underlying database (i.e., not in MySQL).
Neither the group by
clause nor the order by
clause can contain arithmetic expressions. Hibernate also does not currently expand a grouped entity, so you cannot write group by cat
if all properties of cat
are non-aggregated. You have to list all non-aggregated properties explicitly.
14.13. Subqueries
For databases that support subselects, Hibernate supports subqueries within queries. A subquery must be surrounded by parentheses (often by an SQL aggregate function call). Even correlated subqueries (subqueries that refer to an alias in the outer query) are allowed.
Note that HQL subqueries can occur only in the select or where clauses.
Note that subqueries can also utilize row value constructor
syntax. See Section 14.18, “Row value constructor syntax” for more information.
14.14. HQL examples
Hibernate queries can be quite powerful and complex. In fact, the power of the query language is one of Hibernate's main strengths. The following example queries are similar to queries that have been used on recent projects. Please note that most queries you will write will be much simpler than the following examples.
The following query returns the order id, number of items, the given minimum total value and the total value of the order for all unpaid orders for a particular customer. The results are ordered by total value. In determining the prices, it uses the current catalog. The resulting SQL query, against the ORDER
, ORDER_LINE
, PRODUCT
, CATALOG
and PRICE
tables has four inner joins and an (uncorrelated) subselect.
What a monster! Actually, in real life, I'm not very keen on subqueries, so my query was really more like this:
The next query counts the number of payments in each status, excluding all payments in theAWAITING_APPROVAL
status where the most recent status change was made by the current user. It translates to an SQL query with two inner joins and a correlated subselect against the PAYMENT
, PAYMENT_STATUS
and PAYMENT_STATUS_CHANGE
tables.
If the statusChanges
collection was mapped as a list, instead of a set, the query would have been much simpler to write.
The next query uses the MS SQL Server isNull()
function to return all the accounts and unpaid payments for the organization to which the current user belongs. It translates to an SQL query with three inner joins, an outer join and a subselect against the ACCOUNT
, PAYMENT
, PAYMENT_STATUS
, ACCOUNT_TYPE
, ORGANIZATION
and ORG_USER
tables.
For some databases, we would need to do away with the (correlated) subselect.
14.15. Bulk update and delete
HQL now supports update
, delete
and insert ... select ...
statements. See Section 13.4, “DML-style operations”for more information.
14.16. Tips & Tricks
You can count the number of query results without returning them:
To order a result by the size of a collection, use the following query:
If your database supports subselects, you can place a condition upon selection size in the where clause of your query:
If your database does not support subselects, use the following query:
As this solution cannot return a User
with zero messages because of the inner join, the following form is also useful:
Properties of a JavaBean can be bound to named query parameters:
Collections are pageable by using the Query
interface with a filter:
Collection elements can be ordered or grouped using a query filter:
You can find the size of a collection without initializing it:
14.17. Components
Components can be used similarly to the simple value types that are used in HQL queries. They can appear in the select
clause as follows:
where the Person's name property is a component. Components can also be used in the where
clause:
Components can also be used in the order by
clause:
Another common use of components is in row value constructors.
14.18. Row value constructor syntax
HQL supports the use of ANSI SQL row value constructor
syntax, sometimes referred to AS tuple
syntax, even though the underlying database may not support that notion. Here, we are generally referring to multi-valued comparisons, typically associated with components. Consider an entity Person which defines a name component:
That is valid syntax although it is a little verbose. You can make this more concise by usingrow value constructor
syntax:
It can also be useful to specify this in the select
clause:
Using row value constructor
syntax can also be beneficial when using subqueries that need to compare against multiple values:
One thing to consider when deciding if you want to use this syntax, is that the query will be dependent upon the ordering of the component sub-properties in the metadata.
https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html