Hibernate criteria query with subquery joining two columns

巧了我就是萌 提交于 2019-11-30 17:40:52
Mark O'Driscoll

Had exactly the same problem and couldn't find an exact solution for a multi-column subquery match. What I did was rewrite the query so that it only needs to match the subselect on ONE column. So instead of

SELECT *
FROM Quote q1
INNER JOIN (
    SELECT id, MAX(date) AS maxdate
    FROM Quote
    GROUP BY id
) q2
    ON q1.id = q2.id AND q1.date = q2.maxdate;

Try:

SELECT *
FROM Quote q1
WHERE q1.date = (SELECT MAX(date) FROM Quote inner where inner.id = q1.id)

The key difference is that all bar the MAX condition of the JOIN criteria is now inside the inner SELECT.

The criteria/detached criteria for this looks like:

DetachedCriteria innerCriteria = DetachedCriteria.forClass(Quote.class, "inner")
    .add(Restrictions.eqProperty("inner.id","q1.id"))
    .setProjection(Projections.projectionList().add(Projections.max("inner.date")));

DetachedCriteria outerCriteria= DetachedCriteria.forClass(ClmClaim.class, "q1");
outerCriteria.add(Subqueries.propertyEq("q1.date", innerCriteria ));

The SQL produced looks like:

select
        this_.<Blah> as blah2_49_0_,
        this_.<Blah> as blah2_50_0_,
        this_.<Blah> as blah2_51_0_,

    from
        Quote this_ 
    where
         this_.date = (
            select
                max(inner_.date) as y0_ 
            from
                Quote inner_ 
            where
                inner_.claim_number=this_.claim_number
        );

You'll note that there is no 'group by' in the SQL because it's not needed. I would expect one to be there if there were more than one match condition in the subselect.

Anyway, hope it helps. It's the last thing I'm going to do before Christmas!

I have a similar use case. I'm pretty sure it can't be done with Criteria. Hibernate doesn't support joins in the from clause: https://hibernate.atlassian.net/browse/HHH-3356 (still open at time of writing).

The Christmas 2013 answer is pretty good, but unfortunately that correlated subquery is really bad in my use-case of:

  • using MySQL
  • there can be thousands of dates for each id

But this one is fine (for MySQL 5.6.25 anyway):

SELECT * FROM Quote q1
WHERE (q1.id, q1.date) IN 
(
    SELECT id, max(date)
    FROM Quote
    GROUP BY id, date
)

I came here looking for an answer to

DetachedCriteria maxDateQry = DetachedCriteria.forClass(Quote.class);
maxDateQry.setProjection(
    Projections.projectionList()
        .add(Projections.groupProperty("qid.id"))
        .add(Projections.max("qid.date", "maxdate"))
    );

Criteria criteria = session.createCriteria(Quote.class);
Object environmentIdAndStartedDateProperty = "(environmentId, startedDate)" // but not this, some sort of magic
criteria.add(
    Subqueries.in(environmentIdAndStartedDateProperty, maxDateQry));
List<Quote> quoteList = criteria.list();

But it looks like no such magic exists. I had to give up and use hql, which is probably for the best because according to the Hibernate 4.2 documentation the hibernate criteria API is deprecated anyway: https://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/apb.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!