14

整数IDと日付の複合キーといくつかの追加列を持つ、休止状態にマップされたテーブル「Quote」があります。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

hibernate では、このような「group by」サブクエリの DetachedCriteria を作成できると思います (ここで、Quote はテーブルをマッピングするクラスであり、「Qid」はキーの複合 ID クラスであり、プロパティ ID と日付があり、 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();

上記の 2 つの Property.forName は、外部テーブルをサブクエリの対応する列に関連付けます。内部結合が 1 つの値しか提供しない場合、DetachedCriteria に単一の Projection を指定し、DetachedCriteria を直接 Property.forName(...).eq(..) に渡します。Projection で 2 つの値 (id と maxdate) を持つ DetachedCriteria を使用する方法がわかりません。

4

2 に答える 2

12

まったく同じ問題があり、複数列のサブクエリの一致に対する正確な解決策を見つけることができませんでした。私がしたことは、クエリを書き直して、1 つの列のサブセレクトのみを一致させる必要があるようにすることでした。だから代わりに

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 に「group by」がないことに注意してください。副選択に複数の一致条件がある場合は、そこにあると思います。

とにかく、それが役立つことを願っています。クリスマス前にやることはこれが最後!

于 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 のドキュメントによると、とにかく hibernate 基準 API は非推奨であるため、これがおそらく最善の方法です: https://docs.jboss.org/hibernate/orm/4.2/devguide/en- US/html/apb.html

于 2016-02-02T09:18:50.453 に答える