Is there any way to write a greatest-n-per-group query in HQL (or potentially with Hibernate Criteria) in a single query?
I'm struggling with a problem that's similar to this:
Schema:
- Book has a publication_date
- Book has an Author
- Author has a Publisher
I have a Publisher in hand, as well as a search date. For all of that Publisher's Authors, I want to find the book that they published most recently before the search date.
I've been trying to get this working (and have looked at many of the other questions under hibernate as well as greatest-n-per-group) but haven't found any examples that work.
In straight MySQL, I'm able to use a subselect to get this:
select * from
(select
a.id author_id,
b.id book_id,
b.publication_date publication_date
from book b
join author a on a.id = b.author_id
join publisher p on p.id = a.publisher_id
where
b.publication_date <= '2011-07-01'
and p.id = 2
order by b.publication_date desc) as t
group by
t.author_id
This forces the order by to happen first in the subquery, then the group by happens afterwards and picks the most recently published book as the first item to group by. I get the author ID paired with the book ID and publication date. (I know this isn't a particularly efficient way to do it in SQL, this is just an example of one way to do it in native SQL that's easy to understand).
In hibernate, I've been unable to construct a subquery that emulates this. I also haven't had any luck with trying to use a having clause like this, it returns zero results. If I remove the having clause, it returns the first book in the database (based on it's ID) as the group by happens before the order by:
Book.executeQuery("""
select b.author, b
from Book b
where b.publicationDate <= :date
and b.author.publisher = :publisher
group by b.author
having max(b.publicationDate) = b.publicationDate
order by py.division.id
""", [date: date, publisher: publisher])
Is there any way to get hibernate to do what I want without having to spin through objects in memory or dive back down to raw SQL?
This is against a MySQL database and using Hibernate through Grails if it matters.