14

我有一个表,“报价”,在休眠中映射,它有一个整数 id 和一个日期的复合键,以及几个附加列。我想编写一个条件查询,该查询使用 DetachedCriteria 来获取每个 id 具有最大日期的行。

在 sql 中,我可能会编写如下查询

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

在休眠中,我认为可以像这样为“group by”子查询创建一个 DetachedCriteria(其中 Quote 是映射表的类,而“Qid”是键的复合 id 类,具有属性 id 和 date,由 a Quote 类的“qid”属性):

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

但是,我不确定如何在与上面的 sql 外部部分等效的条件查询中使用它。我正在寻找类似的东西

Criteria criteria = session.createCriteria(Quote.class);
criteria.add(
    Restrictions.and(
        Property.forName("qid.id").eq(maxDateQry???),
        Property.forName("qid.date").eq(maxDateQry???)));
List<Quote> quoteList = criteria.list();

上面的两个 Property.forName 将外部表与子查询的相应列相关联。如果内部连接只提供一个值,我将简单地给 DetachedCriteria 一个单一的 Projection,并将 DetachedCriteria 直接传递给 Property.forName(...).eq(..)。我不确定如何在 Projection 中使用具有两个值(id 和 maxdate)的 DetachedCriteria。

4

2 回答 2

12

有完全相同的问题,无法找到多列子查询匹配的确切解决方案。我所做的是重写查询,以便它只需要匹配 ONE 列上的子选择。所以而不是

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;

尝试:

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

关键区别在于,所有 JOIN 条件的 MAX 条件现在都在内部 SELECT 内。

对此的标准/分离标准如下所示:

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 ));

生成的 SQL 如下所示:

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
        );

您会注意到 SQL 中没有“分组依据”,因为它不是必需的。如果子选择中有多个匹配条件,我希望会有一个。

无论如何,希望它有所帮助。这是圣诞节前我要做的最后一件事!

于 2013-12-20T15:45:44.397 回答
4

我有一个类似的用例。我很确定它不能用标准来完成。Hibernate 不支持 from 子句中的连接:https ://hibernate.atlassian.net/browse/HHH-3356 (在撰写本文时仍然开放)。

2013 年圣诞节的答案非常好,但不幸的是,相关子查询在我的用例中非常糟糕:

  • 使用 MySQL
  • 每个 id 可以有数千个日期

但是这个很好(无论如何对于 MySQL 5.6.25):

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

我来这里是为了寻找答案

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();

但似乎不存在这样的魔法。 我不得不放弃并使用 hql,这可能是最好的,因为根据 Hibernate 4.2 文档,无论如何不推荐使用休眠标准 API:https ://docs.jboss.org/hibernate/orm/4.2/devguide/en-美国/html/apb.html

于 2016-02-02T09:18:50.453 回答