整数IDと日付の複合キーといくつかの追加の列を持つHibernateにマップされたテーブル「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では、次のように「groupby」サブクエリの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(..)に直接渡します。プロジェクションで2つの値(idとmaxdate)を指定してDetachedCriteriaを使用する方法がわかりません。
まったく同じ問題があり、複数列のサブクエリの一致に対する正確な解決策を見つけることができませんでした。私がしたことは、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には「groupby」がないことに注意してください。副選択に複数の一致条件がある場合は、そこにあると思います。
とにかく、それが役立つことを願っています。それは私がクリスマスの前にやろうとしている最後のことです!
同様のユースケースがあります。 Criteriaではできないと確信しています。 Hibernateはfrom句の結合をサポートしていません: https://hibernate.atlassian.net/browse/HHH-3356 (執筆時点ではまだ開いています)。
2013年のクリスマスの答えはかなり良いですが、残念ながら、相関サブクエリは私のユースケースでは本当に悪いです:
しかし、これは問題ありません(とにかく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