API-интерфейс Hibernate Criteria - HAVING работает вокруг
Я написал запрос с использованием Hibernate Criteria API, чтобы получить суммирование определенного значения, теперь мне нужно ограничить результат строками, где эта сумма больше или равна определенному значению.
Обычно я бы использовал предложение HAVING в своем SQL для этого, но API-интерфейс Criteria API, похоже, не поддерживает это в данный момент.
В сыром SQL это то, что мне нужно:
SELECT user_pk, sum(amount) as amountSum
FROM transaction
GROUP BY user_pk
HAVING amountSum >=50;
Одна работа, о которой я думал, заключается в использовании подзапроса в предложении FROM, который захватывает это суммирующее значение и использует внешний запрос для ограничения его с помощью предложения WHERE.
Итак, в raw SQL он будет выглядеть примерно так:
SELECT user_pk, amountSum
FROM (SELECT user_pk, sum(amount) as amountSum
FROM transaction
GROUP BY user_pk)
WHERE amountSum > 50;
Может ли кто-нибудь указать мне в правильном направлении, как я могу написать это, используя API критериев или любые другие предложения/варианты работы, которые я могу использовать для решения проблемы HAVING?
Это код API критериев, который у меня есть для приведенного выше примера
DetachedCriteria criteria = DetachedCriteria.forClass(Transaction.class,"transaction");
criteria.setProjection(criteria.setProjection(Projections.projectionList().add(
Projections.groupProperty("user.userPK").as("user_pk")).add(
Projections.sum("transaction.amount").as("amountSum")));
Спасибо!
Ответы
Ответ 1
Я не знаю, как Hibernate/NHibernate использовать подзапрос в предложении FROM, но вы можете использовать их в предложении WHERE.
Извиняюсь за любые ошибки кода Java/Hibernate, я больше знаком с С#/NHibernate.
DetachedCriteria subQuery = DetachedCriteria.forClass(Transaction.class);
subQuery.setProjection(Projections.sum("amount"));
subQuery.add(Expression.eqProperty("userPk", "tOuter.userPk"));
DetachedCriteria outerQuery = DetachedCriteria.forClass(Transaction.class, "tOuter");
outerQuery.setProjection(Projections.projectionList()
.Add(Projections.sum("amount").as("sumAmount"))
.Add(Projections.groupProperty("userPk").as("user_pk"));
outerQuery.add(Subqueries.le(50, subQuery));
Этот код должен привести к тому, что SQL похож на:
SELECT tOuter.userPk as user_pk, sum(tOuter.amount) as sumAmount
FROM transaction tOuter
WHERE 50 <= (SELECT sum(amount) FROM transaction WHERE userPk = tOuter.userPk)
GROUP BY tOuter.userPk
Недостатком этого подхода является то, что он вычисляет каждую из сумм дважды, это может иметь пагубное влияние на производительность в зависимости от объема данных - в этом случае вы захотите использовать запрос HQL, который поддерживает HAVING пункт.
Ответ 2
HHH-1700 был отмечен как дубликат HHH-1043 и поэтому не будет исправлен. Вы найдете решение и обходное решение, а также другие народы, на HHH-1043.
Ответ 3
http://opensource.atlassian.com/projects/hibernate/browse/HHH-1700